内容发布更新时间 : 2024/12/29 13:23:00星期一 下面是文章的全部内容请认真阅读。
龙源期刊网 http://www.qikan.com.cn
面向对象设计中的设计原则实践
作者:谷艳昭 苏贵斌 曹森 来源:《软件导刊》2012年第02期
摘 要:列举了一些面向对象编程中的基本设计原则,分析了这些设计原则的具体使用环境,说明了如何在系统中实现这些设计原则。
关键词:软件开发;面向对象;设计原则;设计原则实现;设计模式 中图分类号:TP301 文献标识码:A 文章编号:1672-7800(2012)002-0025-
作者简介:谷艳昭(1986-),男,河北石家庄人,内蒙古师范大学计算机与信息工程学院硕士研究生,研究方向为软件工程与集成技术;,苏贵斌(1968-),男,黑龙江望奎人,硕士,内蒙古师范大学计算机与信息工程学院副教授,研究方向为软件开发与集成技术;曹森(1986-),男,安徽临泉人,内蒙古师范大学硕士研究生,研究方向为软件开发与集成技术。
1 接口隔离原则
接口隔离原则(Interface Segregation Principle常缩写为ISP)是说使用多个专门的接口比使用单一的总接口要好。这里的接口往往有两种不同的含义:一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;另一种是指某种语言具体的接口定义,有严格的定义和结构.比如Java语言里面的Interface结构。对于这两种不同的含义,ISP的表达方式以及含义都有所不同。
当我们把接口理解成一个类所提供的所有方法的特征集合的时候,这就是一种逻辑上的概念。这里,我们可以把接口理解成角色,一个接口就只是代表一个角色,每个角色都有它特定的一个接口。
如果把接口理解成狭义的特定语言的接口,那么ISP表达的意思是说,对不同的客户端,同一个角色提供宽窄不同的接口,也就是定制服务,个性化服务。就是仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来。
龙源期刊网 http://www.qikan.com.cn
在我们进行OOD的时候,一个重要的工作就是恰当的划分角色和角色对应的接口。将没有关系的接口合并在一起,是对角色和接口的污染。如果将一些看上去差不多的接口合并,并认为这是一种代码优化,这是错误的.不同的角色应该交给不同的接口,而不能都交给一个接口。 分离接口的方式一般分为两种:①使用委托分离接口。把请求委托给别的接口的实现类来完成需要的职责,就是适配器模式;②使用多重继承分离接口。该方法通过实现多个接口来完成需要的职责。
两种方式各有优缺点,通常我们应该先考虑后一个方案,如果涉及到类型转换时则选择前一个方案。如果已经设计成了胖接口,可以使用适配器模式隔离它。 2 里氏替换原则
里氏替换原则(常缩写为LSP)的严格表达是:“如果对于每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换为O2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。”LSP原则要求子类可以无条件的替代父类,子类不能对父类没有暴露的接口进行扩展,客户要调用功能只能通过父类暴露的接口来调用不能擅自向子类调用。
据Bertrand Meyer氏提出的Design by Contract概念的描述,对于类的一个方法,都有一个前提条件以及一个后续条件,把前提条件以及后续条件应用到继承子类中,子类方法应该满足:①前提条件不强于基类;②后续条件不弱于基类。
即通过基类的接口调用一个对象时,用户只知道基类前提条件以及后续条件。因此继承类不得要求用户提供比基类方法要求的更强的前提条件,同样,继承类必须顺从基类的所有后续条件,不能让用户对继承类方法的输出感到困惑。 具体到java语言来说,可以用下面两个类来说明:
System.out.println(\这是父类
System.out.println(\这是子类
龙源期刊网 http://www.qikan.com.cn
}}
子类的前提条件不强于基类指的是在子类重写父类的方法时,所重写的方法的参数的数据类型可以与父类相同或者比父类更抽象。子类方法的后续条件不弱基类是指在子类重写父类的方法时,所重写的方法的返回值类型和抛出的异常的数据类型可以与父类相同或者比父类更具体,如果子类不能按上面的要求实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖,聚合等关系代替继承。 3 迪米特法则
迪米特法则又叫作最少知识原则(Least Knowledge Principle 简写LKP),是说一个对象应当对其他对象有尽可能少的了解。
这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中的一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,它需要花许多成本维护。
按这一原则的一些指导方针,就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:①属于该对象本身;②被当作方法的参数而传递进来的对象;③此方法所创建或实例化的任何对象。
如果调用从另一个调用中返回的对象的方法,会有什么害处呢?如果我们这样做,相当于向另一个对象的子部分发请求(从而增加我们直接认识的对象的数目)。这种情况下,原则要我们改为要求该对象为我们做出请求。
在将迪米特法则运用到系统的设计中时,应注意的几点:①在类的划分上,应该创建有弱耦合的类;类之间的耦合越弱,就越有利于复用;②在类的结构设计上,每一个类都应当尽量降低成员的访问权限。一个类公开的public属性或方法越多,修改时涉及的面也就越大,变更引起的风险扩散也就越大;③只要有可能,一个类应当设计成不变类;一个类的内部状态创建后,在整个生命期间都不会变化时,这样的类称作不变类,比如:String,BigInteger,BigDecimal等。具体到JAVA语言来说,就是在定义类的时候尽量用final来定义类的属性和方法,使定义的类尽可能少的与其他类发生关系,从根本上减少其它类对本类的了解;④谨慎使用序列化功能。一个类如果实现了Serializable接口的话,客户端就可以将这个类的实例串行化,然后再并行化。由于串行化和并行化涉及到类的内部结构,如果这个类的内部private结构在一个新版本中发生变化的话,那么客户端可能会根据新版本的结构试图将一个老版本的串行化结果并行化,这会导致失败。
换言之,为防止这种情况发生,软件提供商一旦将一个类设置成为Serializable的,就不能再在新版本中修改这个类的内部结构,包括private的方法。 4 依赖倒转原则