文档介绍:软件设计模式
第2章面向对象程序设计原则
提纲
单一职责原则(SRP)
“开/闭”原则(OCP)
接口隔离原则(ISP)
依赖倒置原则(DIP)
Liskov替换原则(LSP)
(客户)类是否会产生影响?
这种依赖关系不受具体实现类型的影响。因此,PayByEBank类的添加也没有影响到客户类Patron。
从可扩展性和代码稳定性角度看,,符合“开/闭”原则的设计思想。
实施“开/闭”原则设计代码时,工程师可以使用抽象、继承、组合等面向对象技术获得代码灵活性、可重用性、可扩展性等方面的好处。但也应看到,“开/闭”原则对代码还有以下的影响:
1)代码可读性降低。由于使用了抽象,代码设计逻辑与业务需求逻辑相比,会产生变化,抽象代码层隐藏了具体业务细节,大大降低了源码的可读性。
2)程序测试成本增加。同样地,使用抽象设计会使测试人员无法静态确定具体对象的引用类型,必须等到程序运行时才能确定目标对象的具体类型。因此,代码缺陷可能会滞后到程序运行后才被发现;又或者,程序出现错误后,只有通过动态调试的方法才能有效地定位缺陷。最终,它们都会导致测试成本的增加。
接口隔离原则(ISP)
接口隔离原则指出:如果某个接口的行为不是内聚的,就应该按照业务分组,并将分组后的业务行为通过隔离的接口单独定义。
接口的行为要向调用它的客户端提供业务服务;对于不同的业务分组,调用它的客户端是相互独立的;
因此,接口提供的服务(分组)也应该是相互独立的。
打印配送单和发送配送指令行为定义在IDeliver接口中
例如,在COS系统需求中,餐厅员工(Cafeteria Staff)和配餐员(Meal Deliverer)都有打印配送单(Print Delivery Instructions)的行为;而且,餐厅员工还有发送配送指令(Issue Delivery Request)的行为。如果将打印配送单行为和发送配送指令行为强行定义在接口IDeliver中,,将会产生如下问题:
1)子类(或实现类)可能会继承(或实现)冗余行为。配餐员MealDeliverer作为IDeliver的实现类,需要实现issueDeliveryQuest()方法;然而,在COS的需求中,配餐员不具有该行为。
2)子类(或实现类)的客户端受到不相干的业务行为干扰。假设餐厅员工CafeteriaStaff想要改变issueDeliveryQuest()的行为定义,比如修改方法名称;那么,则要修改接口IDeliver。而IDeliver接口的变化会导致实现类MealDeliverer变化,最终影响到调用MealDeliverer的所有客户端。
要解决上面的问题,工程师可以按照接口隔离原则提供的建议将接口中的方法进行业务分组。由于打印打印配送单和发送配送指令是不同的业务行为,两者之间的内聚度很弱,分离它们可以降低相互影响。
使用“接口隔离”原则设计打印配送单和发送配送指令行为
因此,()和issueDeliveryQuest()分别定义在的接口IPrintDelivery和IIssueDelivery中,用于实现行为的隔离;。
IIssueDelivery接口定义了issueDeliveryQuest()行为,IPrintDelivery接口定义了printDeliveryInstruction()行为,彼此独立,互不影响。CafeteriaStaff类实现IIssueDelivery、IPrintDelivery接口,MealDeliverer实现IPrintDelivery接口。
可以看到,MealDeliverer只实现了自身需要的业务行为printDeliveryInstruction(),不用实现冗余行为issueDeliveryQuest(),保证了代码逻辑与需求的一致性。此外,IIssueDelivery接口定义的变化只对其实现类CafeteriaStaff产生影响,而不会对MealDeliverer造成任何影响。
。
IIssueDelivery接口:
IPrintDelivery接口:
在Java编程语言中,IPrintDelivery接口可以定义printDeliveryInstruction()行为的默认实现,CafeteriaStaff、MealDeliverer根据需求选择重写或使用接