OO第三阶段Blog作业

1,前言

这次题目集内容一个是图形卡片的排序分组,一个是ATM机系统的结构设计,没有了之前的作业中的那些“简单小题目”。图形卡片分成了排序和分组两次作业,其实区别不大,主要是改变了排序的规则。ATM机进行了一次迭代,增加了一个信用卡借贷功能。
图形卡片排序以及分组利用多态实现不同图形获取面积的设计,然后排序分组需要用到Comparable或Comparator接口实现类的排序规则。ATM机系统难点在于理解ATM系统里的一些概念,并将这些概念设计成实体类。
程序的设计需要考虑“单一职责”原则,“开-闭”原则和“合成复用原则”。由于我面向对象程序设计的经验不多,也不够了解设计程序的具体方法,因此最终的程序和预期设想的还是有比较大的出入,设计上没有很符合这些设计原则。
这三次题目集的个人认为难度较大,主要体现在设计上,因为这次的作业内容较之前的更多,虽然算法难度小,但设计难度较大,在设计时很难理清思路,因此在写这阶段的作业时设计程序时花了特别多的时间。

2,设计与分析

题目集7两道题目(图形卡片)的递进式设计分析

图形卡片排序

将图形抽象成一个抽象类,并设计抽象方法来获取面积和校验数据的合法性。不同形状的图形继承抽象图形类,因为面积是由图形的其他数据计算得来的,因此不设计成类的属性。再设计一个Card类实现comparable接口,通过对比卡片里的图形面积来得到比较结果。

卡片类和图形类代码

/**
 * 卡片类
 * @author YMzs
 */
class Card implements Comparable<card> {
	Shape shape;

	public Shape getShape() {
		return shape;
	}

	public void setShape(Shape shape) {
		this.shape = shape;
	}

	public Card() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Card(Shape shape) {
		super();
		this.shape = shape;
	}

	@Override
	public int compareTo(Card o) {
		return (int) Math.round(this.getShape().getArea() - o.getShape().getArea());
	}
}
/**
 * 图形类
 * @author YMzs
 */
abstract class Shape {
	private String shapeName = "";

	public Shape() {
		super();
		this.shapeName = this.getClass().getSimpleName();
	}

	public Shape(String shapeName) {
		super();
		this.shapeName = shapeName;
	}

	public String getShapeName() {
		return shapeName;
	}

	public void setShapeName(String shapeName) {
		this.shapeName = shapeName;
	}

	/**
	 * 获取图形面积
	 * 
	 * @return
	 */
	public abstract double getArea();

	public abstract boolean validate();

	public String toString() {
		return shapeName + ":" + String.format("%.2f", this.getArea());
	}

}

类图

image

圈复杂度

image
image

图形卡片分组

和前一道题目区别不大,我的方法是在原来的基础上对卡片按不同类型进行分组。还有一个办法是在排序规则上作修改,将图形类型也作为排序的依据,但是这样排序的话只是“表面上”的分组,实际上卡片还是在一个卡片列表里,如果需要对不同组的卡片进行处理,比如计算相同图形卡片的总面积就会比较麻烦。

卡片分组代码

/**
 * 卡片处理业务类
 * @author YMzs
 *
 */
class DealCardList {
	private ArrayList<card> cardList = new ArrayList<card>(); // 所有卡片列表
	private HashMap<string, cardgroup=""> cardGroup = new HashMap<>(); // 不同类型卡片分组,CardGroup为一个卡片组类

	/**
	 * 对卡片进行分组
	 */
	public void groupping() {
		for (Card eachCard : cardList) {
			String cardName = eachCard.getShape().getShapeName();
			cardGroup.putIfAbsent(cardName, new CardGroup(cardName));
			cardGroup.get(cardName).add(eachCard);
		}
	}
	
	...
}

类图

image

圈复杂度

image
image

可以看出确实和上一道题区别不大

ATM机类结构设计(一)

ATM机系统有这么几个概念:中国银联,银行,银行用户,银行账户,银行卡,ATM机。设计要求是均要有对应的实体类。
中国银联,银行卡,ATM机这三个概念还比较简单,银行隶属于中国银联,卡属于银行的账户,ATM隶属于不同的银行。但银行,银行账户和银行用户三者的关系就比较复杂,银行和银行用户都和银行账户有关联,设计时我没有考虑好这部分,设计上只有银行用户和银行账户产生关联。
还有一个难题是在存取款,查询时,输入的数据有卡号,密码,ATM机编号,金额,那么如何利用这些数据找到对应的银行账户呢?一个办法是根据卡号去中国银联询问每个银行,再去银行里询问每个银行账户是否存在该卡号,如果数据少还行,如果数据大的话每次查询就会很费时间。而且之前已经说了我的设计上是有一点问题的,银行和银行账户并没有关联,因此我的做法是建一个“数据库”,在创建各种信息的时候添加不同数据的关联信息,这样在查询时直接去询问有无此数据即可。比如用一个卡号到卡的映射(HashMap)获取卡信息,用卡到银行的映射获取卡所属银行信息等。个人认为这并不是一个特别好的方案,因为这样各数据间的关系就十分的混乱,而且复用性和可维护性不高。

类图

image

圈复杂度

image
image

ATM机类结构设计(二)

这次的代码是在上次老师给的参考代码基础下重构的(老师要求),不过老师在代码中留了坑。
老师代码的寻找对应卡的方法是之前我说的前者,对已存在的卡进行遍历。实体类和我设计的不同在于把关联的信息分散在了每个实体类内部,比如说账户的属性有用户、卡、银行,而银行、用户、卡的属性也有账户,这样就实现了双向的查找。再结合找卡的方法,就可以透过卡号找到所有相关的信息。
对老师给的代码进一步重构,增加信用卡借贷功能。将银行卡和银行账户抽象成一个类,然后分别设计信用卡和借贷卡,借记账户和贷记账户。账户类新增一个获取取款限额方法,贷记账户的取款限额与中国银联设定的透支额度有关。
老师的代码在取款中校验取款的合法性,这不符合单一职责原则,因此将校验独立设计成一个类。

类图

image

圈复杂度

image
image
image
image
image
image
image
image
image
image
image
image
image
image
image

3,踩坑心得

手续费的计算方法

这或许是吃了没有办过信用卡贷过款的亏,一开始看要求以为透支取款收的手续费为所有取款金额的5%,结果测试了即便还是过不了样例,后面用计算机算的也和样例对不上,最后问了同学才知道透支取款收的手续费实际上应为透支金额的5%。

4,改进建议

ATM第二次迭代获取银行卡以及获取ATM机的方法

可以用HashMap来建立卡号到银行卡的映射,ATM机同理,这样能提高获取银行卡和ATM机的效率。

5,总结

收获

学会了使用Comparable或Comparator接口,这样就能对自己设计的类指定排序规则了。
因为ATM的设计老师并没有给设计类图,因此所有的类都是自己设计的,能明显感觉到设计一个程序不是那么容易的,几大设计原则看似简单,在设计时考虑周全其实是很难的,也通过两次迭代明白了设计良好的程序优秀的可维护性和拓展性。

posted @ 2021-06-20 23:00  云墨zs  阅读(46)  评论(0)    收藏  举报