JAVA继承实战:福彩3D奖金计算系统设计与实现
1. 福彩3D奖金计算系统需求分析福彩3D作为国内流行的数字型彩票游戏其奖金计算规则复杂多样。不同玩法对应不同的中奖条件和奖金金额这对程序的设计提出了较高要求。比如单选玩法要求数字和位置完全匹配奖金高达1040元而组选玩法只需数字相同即可奖金则根据是否有重复数字分为346元和173元两种。在实际业务场景中我们需要处理用户同时投注多种玩法的情况。比如一个用户可能既买了单选456又买了组选456还买了1D投注4。这时系统需要自动判断每种玩法的中奖情况并找出最高奖金金额。这种多玩法并存的特性正是我们使用面向对象设计中继承机制的最佳场景。提示奖金计算的核心难点在于处理不同玩法间的规则差异而继承机制恰好可以帮助我们抽象共性、隔离变化。2. 面向对象设计思路2.1 抽象类设计我们首先定义一个抽象基类Lottery它包含了所有玩法共有的属性和方法abstract class Lottery { protected int[] winNumber; // 开奖号码 protected int[] userNumber; // 用户投注号码 protected String userInput; // 用户原始输入 // 构造函数初始化开奖号码 Lottery(String s) { winNumber createWinNumber(s); } // 将字符串转换为数字数组 int[] createWinNumber(String s) { int[] winnu new int[3]; try { Integer i Integer.valueOf(s); if (i 0 i 1000) { for (int j 0; j 3; j) { winnu[2 - j] i % 10; i i / 10; } return winnu; } } catch (Exception e) { return null; } return winnu; } // 抽象方法由子类实现具体玩法规则 abstract int getwinlevel(int[] winnumber, String s); }这个抽象类完成了两件重要工作一是定义了所有子类都需要用到的开奖号码处理逻辑二是声明了奖金计算的抽象方法强制子类必须实现自己的规则判断。2.2 具体玩法实现以单选玩法为例我们创建Single子类继承Lottery基类class Single extends Lottery { Single(String s) { super(s); } Override int getwinlevel(int[] winnumber, String s) { this.getUserInput(s); boolean win true; for (int i 0; i userNumber.length; i) { if (userNumber[i] ! winnumber[i]) { win false; break; } } return win ? 1040 : 0; } }单选玩法的规则非常简单 - 只需要逐位比较用户号码和开奖号码即可。如果全部匹配则返回1040元奖金否则返回0。相比之下组选玩法的实现就复杂一些。以组选3为例class Group extends Lottery { // 对号码进行排序处理 int[] arrange(int[] winnumber) { int[] newwinnumber Arrays.copyOf(winnumber, winnumber.length); Arrays.sort(newwinnumber); return newwinnumber; } Override int getwinlevel(int[] winnumber, String s) { if (!this.getUserInput(s)) return 0; int[] newwinnumber arrange(winnumber); int[] newuserinput arrange(this.userNumber); // 判断是否为组选3有两个重复数字 int maxequal 0; for (int i 0; i newwinnumber.length - 1; i) { if (newwinnumber[i] newwinnumber[i 1]) { maxequal; } } // 比较排序后的号码 boolean equals Arrays.equals(newwinnumber, newuserinput); if (equals) { return maxequal 1 ? 346 : 173; } return 0; } }组选玩法需要先将号码排序然后判断重复数字情况最后比较排序后的号码是否一致。这种处理方式完美体现了面向对象的一个核心原则 - 将变化封装在子类中对外提供统一的接口。3. 系统核心实现细节3.1 工厂方法模式应用为了灵活创建各种玩法实例我们采用了工厂方法模式public static Lottery getusertype(String s, String wins) { switch (s) { case single: return new Single(wins); case group: return new Group(wins); case oned: return new Oned(wins); case guess1d: return new Guess1d(wins); case sum: return new Sum(wins); case tractor: return new Tractor(wins); case general: return new General(wins); case package: return new Package(wins); case towd: return new Towd(wins); default: return null; } }这种设计使得新增玩法变得非常简单 - 只需要创建新的子类并在工厂方法中添加一个case即可完全不影响现有代码。3.2 多玩法奖金计算主程序处理逻辑如下public static void main(String[] arg) { Scanner s new Scanner(System.in); String wins s.next(); // 开奖号码 int times s.nextInt(); // 玩法数量 int maxlevel 0; for (int i 0; i times; i) { String type s.next(); // 玩法类型 Lottery l getusertype(type, wins); String userinput type.equals(tractor) ? null : s.next(); int curr l.getwinlevel(userinput); maxlevel Math.max(maxlevel, curr); } System.out.println(maxlevel); s.close(); }这段代码展示了系统的核心流程读取开奖号码和用户投注为每种玩法创建对应的计算实例调用统一的getwinlevel方法获取奖金最后输出最高奖金金额。4. 特殊玩法实现技巧4.1 1D投注处理1D投注只需要匹配特定位置的数字其实现方式很有特点class Oned extends Lottery { Override int getwinlevel(int[] winnumber, String s) { this.getUserInput(s); int place 0, target 0; // 解析投注位置和数字 for (int i 0; i 3; i) { if (s.charAt(i) 0 s.charAt(i) 9) { place i; target s.charAt(i) - 0; } } return target winnumber[place] ? 10 : 0; } }这里巧妙利用了字符串解析技术通过遍历输入字符串找到数字及其位置然后只比较对应位置的数字。4.2 和数玩法奖金表和数玩法根据三个数字之和对应不同的奖金我们采用查表法实现class Sum extends Lottery { private static final int[] PRIZE_TABLE { 1040, 345, 172, 104, 69, 49, 37, 29, 23, 19, 16, 15, 15, 14 }; Override int getwinlevel(int[] winnumber, String s) { this.getUserInput(s); int sum1 Integer.valueOf(s); int sum2 winnumber[0] winnumber[1] winnumber[2]; if (sum1 ! sum2) return 0; // 处理对称情况 if (sum1 13) sum1 27 - sum1; return PRIZE_TABLE[sum1]; } }使用静态数组存储奖金表既提高了效率又使代码更加清晰。对于和数13以上的情况利用对称性简化了判断逻辑。