1 给出一个 Java ADT 题目
某公司拟设计和开发一个停车场管理系统,其基本需求陈述如下:
(1) 一个停车场有 n 个车位(n>=5),不同停车场包含的车位数目不同。
(2) 一辆车进入停车场,如果该停车场有空车位且其宽度足以容纳车的宽度,则可以
在此停车。
(3) 停在停车场里的车,随时可以驶离停车场,根据时间自动计费(每半小时 10
元,不足半小时按半小时计算)。
(4) 停车场管理员可以随时查看停车场的当前占用情况。
![](https://img-blog.csdnimg.cn/f56c1c14583545e49a6664b4c4baa2ff.png)
分析客户端的需求:
采用名词分析法和动词分析法,即提炼出名词和动词来识别自己需要构造的ADT。
名词:停车场、车、车位、车位的宽度、车的宽度、入场时间、出场时间、一次停车得全过程
动词:停车、 驶离、计费、查看状态。
简要列出名词和动词之后可以初步列出想要构造得adt
停车场包含车位数
车包含车牌号、车的宽度
车位包含编号、车位宽度
设计原则:尽可能缩小mutable的范围
一次停车的全过程这个名词有些复杂,涉及到车、入场时间、出场时间、所在车位、费用,不同策略如下:
本次采用第四种方法,即停车场类中管理一次停车的全过程。
编程方法:考虑到将来变化与不同的实现方式,采用接口设计停车场ADT
设计接口的过程:
1.写spec
2.识别ADT的四种操作类型
Parking(Car c,Lot lot)中自己构造的具体对象建议隐藏,传入所需的基本信息在函数中构造,如果不希望把 Car 暴露出去,可改成 parking(String plate, int width, int num), parking(String plate, int width)
需求中的特殊情况怎么处理?
停车进场的时候(两种情况):该车辆已经在停车场里面了
停车进场的时候(不指定车位):停车场已没有可供该车停车的位置
停车进场的时候(指定车位):该车位已被占用、该车位过窄、没有该车位
驶离停车场的时候:该车并没有停在这里
建议的处理方式:
更强的规约:更弱的前置前置、更强的后置条件,让 client 使用更容易,把责任
放在实现者身上。
太弱的 spec,client 不放心、不敢用 (因为没有给出足够的承诺)。开发者应尽
可能考虑各种特殊情况,在 post-condition 给出处理措施。
惯用做法是:不限定太强的 precondition,而是在 postcondition 中抛出异常:
输入不合法。
例如:针对“停车进场的时候(不指定车位),停车场已没有可供该车停车的位置“这
种情况,无法限定 client 已知停车场是否已满,所以不能在 pre 里写,而是交给
post 来处理。
所以,可以针对上述特殊情况,在 post 里使用异常,告知 client。
考虑到目前尚未学习如何定义异常,这里先采用通用的异常类 Exception。
静态工厂方法和实例方法的测试,分开。让测试类的职责更清晰。
使用
Factory Method
设计模式:可维护性
![](https://img-blog.csdnimg.cn/d3dbbba39c4743118e523b0f000838b7.png)
建立一个用于装饰的基础类ComplexParkingField
,实现ParkingField接口,其中的所
有方法都delegate到未装饰之前的对象。
然后,建立一个具体装饰类ParkingFieldWithCompany,也实现ParkingField接口,继
承自ComplexParkingField类,增加了rep(公司信息),对需要变化的方法进行扩展 (使用super.xxx()调用基础功能)。修改构造函数,增加company参数。例如:
@Override
public double depart(String plate) throws Exception {
double price = super.depart(plate);
println(plate + ", " + company + " wish you a good drive");
return price;
}
使用 Visitor 设计模式:可扩展性
建立 visitor 接口 ParkingVisitor,只有一个方法 double visit(parkingField
pf)。
建立其子类 PercentageVisitor,实现该 visit 方法,调用 pf 的方法获得 pf 的内
部表示,进行计算。
在 ParkingField 接口中增加 accept(ParkingVisitor pv)方法,其实现很简单:
pv.visit(this)。
客户端只需要使用 double ratio = pf.accept(new PercentageVisitor())即可。 如果要为 ParkingField 扩展另一个操作呢?只需要构造 ParkingVisitor 的另一个子类 型,在其 visit()中实现新功能,客户端调用 pf.accept()的时候传入新子类的对象即可。
使用
Strategy
设计模式:可扩展性、可维护性
ParkingField 接口中定义了一个方法 void parking(String type, String plate, int width),与另一个带有 num 车位号的 parking 方法相比,使用该方法的 client 端无 需提供“停车位号码”信息,而是在方法内部自动进行空闲停车位的选择。现实中有不同的停 车位选择方法,例如:
(1) 随机选择一个空闲的、宽度大于车辆宽度的停车位;
(2) 根据停车位编号,优先选择编号最小的空闲停车位,且其宽度大于车辆宽度。
使用 Strategy 设计模式改造现有设计:在客户端代码调用 void parking(String type, String plate, int width)的时候,
如何动态传入某个特定的停车位选择方法?
本质上,相当于写两个停车位选择算法,但不直接在 ConcreteParkingField 里写,而是
delegate 出去到外部的 Strategy 具体实现类,跟上面的几个设计模式非常像。
最终停车场整体类图
![](https://img-blog.csdnimg.cn/d615f53a9a4744ad825e6af3fc935b12.png)