前言:
十月份中旬的时候,面向对象的课程项目出来了.3个题目,个人认为都不是很难
- 一个是 Java排序包的实现<要求体现 OO的编程思想,必做>
- 面向对象的纸牌
- 面向对象的音乐播放器(要求有波形图和界面)
2.3是选做其中一个,当时为了早些交上(其实真实目的是为了装X...= =|),所以选择了前两个.看了一下有关纸牌的游戏规则,连思路都没想好就开始写,3天以后就交了,本来以为自己写的还不错,最后交上去了还是最早的.当时很是得瑟了一阵...可是最后看了一眼别人交上去的代码,不仅仅在代码的质量,复用度,还是实现思路上,都有比自己优秀的多的地方.细活出精品啊,自己还是没有理解为什么要把这个项目的时间放宽,就是为了让我们更好地,有更充裕的时间去写出更好,更优秀的代码.这个系列的3篇文章主要是记录两个版本的纸牌(一个是自己的渣渣版本,另个是学姐写的让我看了以后内牛满面的优秀作品...唉,稍稍对比一下就会发现自己的差距),以备以后查阅 以及 加深对Swing技术与 面向对象 OO的理解.这里是第一篇,对优秀版本代码的解读.
一.整体框架的阅读:
-
- 不多说,先上整体的结构组织图:实际运行的效果与布局图 首先看看CardMethod(实际为model)中的类Card:
组织结构十分清晰明了,为了后面判断的方便,这里加入了一个isRed的属性,在后面判断牌堆是否异色,移动是否合法的时候会用到此冗余属性.但是个人这里有个缺点,在没有定义 颜色 与 号码的对应情况下,52张牌用取余来决定于判断花色,让人有不直观的感觉,个人觉得应该在这个类里面定义static final 常量,这样才能够更直接的反映花色.package CardMethod; public class Card { private int suit;//1-4 private int rank;//1-13 private boolean isRed; private boolean faceUp; private int num;//1-52 public Card(int n) { num=n; if(n%13==0) { suit=n/13; rank=13; } else { suit=n/13+1; rank=n%13; } if(suit%2==1) isRed=true; else isRed=false; faceUp=false; } public boolean isFaceUp() { return faceUp; } public void setFaceUp(boolean on) { faceUp=on; } public int getSuit() { return suit; } public boolean isRed() { return isRed; } public int getNum() { return num; } public int getRank() { return rank; } }
- 作者十分精明的观察到了整个游戏内的几个组件都有共同的特性(这一点在和自己源码的对比中还会说到).这也是我在第一次的实际中看到Abstract Class的运用,一个ArrayList<Card>的组织划分,让所有的组件对自己区域内的卡片有了统一的操作规范.这是非常重要的,另外,这里使用了继承,极大的减轻了设计不同模块的代码冗余的负担.自己以前在书本上看到过那种"没有使用继承而带来的垃圾代码过多的现象"在实际项目开发的时候,就这样不知不觉的发生在了我的身上,这对于自诩为"对OO思想了解透彻的"我来讲是不可想象的.代码虽然没有注释,但是结构清晰合理,让人一看便知:
package CardMethod; import java.util.ArrayList; public abstract class CardPile { public ArrayList<Card> pokers; public CardPile() { pokers=new ArrayList<Card>(); } public int getSize() { return pokers.size(); } public Card getTop()//获得牌堆顶牌 { if(pokers.size()>0) return pokers.get(pokers.size()-1); return null; } public Card getCard(int index) { return pokers.get(index); } public boolean isEmpty() { if(pokers.size()>0) return false; return true; } public void addCard(CardPile pile,int index) { for(int i=index;i<pile.getSize();i++) pokers.add(pile.getCard(i)); } public void removeCard(int index)//从顶牌开始删除size-index张牌 { int size=getSize(); for(int i=size-1;i>=index;i--) pokers.remove(i); } public abstract int getCardIndex(int suit,int rank);//对于suitPiles获得应该放入suit的 位置public abstract int getCardIndex(boolean isRed,int rank);//获得第一张颜色相反的牌,用于同时移动几张已排好的牌}
- 接下来其他的几个模型(如 deck pile ,discard pile ,table piles ,suit piles ),都是用了继承自以上的 CardPile.代码复用效果非常好,但是有的组件,如deckpile是用不到这里的两个abstract方法的,也必须实现.这个在设计中是否有规避的办法?值得思考
package CardMethod; public class DeckPile extends CardPile { public void initadd(Card card) { pokers.add(card); } @Override public void addCard(CardPile pile, int index) // 增加牌。 { // TODO Auto-generated method stub for (int i = index; i >= 0; i--) { pokers.add(pile.getCard(i)); } pile.getTop().setFaceUp(false); } @Override public int getCardIndex(int suit, int rank) { // TODO Auto-generated method stub return -1; } @Override public int getCardIndex(boolean isRed, int rank) { // TODO Auto-generated method stub return -1; } }
package CardMethod; //丢弃堆 public class DiscardPile extends CardPile { public void clear() { pokers.clear(); } public void addCard(CardPile pile, int index) { // TODO Auto-generated method stub super.addCard(pile, index); if (!isEmpty()) this.getTop().setFaceUp(true); } public void removeCard(int index) { // TODO Auto-generated method stub super.removeCard(index); if (!isEmpty()) this.getTop().setFaceUp(true); } public int getCardIndex(int suit, int rank) { // TODO Auto-generated method stub if (!this.isEmpty() && this.getTop().getSuit() == suit && this.getTop().getRank() == rank) return this.getSize() - 1; return -1; } @Override public int getCardIndex(boolean isRed, int rank) { // TODO Auto-generated method stub if (!this.isEmpty() && this.getTop().isRed() != isRed