为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

6最少依赖原则

2013-05-23 43页 ppt 584KB 32阅读

用户头像

is_550089

暂无简介

举报
6最少依赖原则null6.最少依赖原则 6.最少依赖原则 合成复用原则 (Composite Reuse Principle, CRP) 迪米特法则 ( Law of Demeter, LoD ) 接口隔离原则 (Interface Segregation Principle, ISP)Composite Reuse PrincipleComposite Reuse Principle“我们的经验表明:设计者往往过度使用了继承这种复用技术。但依赖于对象组合技术的设计却有更好的复用性(或更简单)” ——《设计模式》,GoF CRP是“代码复用...
6最少依赖原则
null6.最少依赖原则 6.最少依赖原则 合成复用原则 (Composite Reuse Principle, CRP) 迪米特法则 ( Law of Demeter, LoD ) 接口隔离原则 (Interface Segregation Principle, ISP)Composite Reuse PrincipleComposite Reuse Principle“我们的经验表明:设计者往往过度使用了继承这种复用技术。但依赖于对象组合技术的设计却有更好的复用性(或更简单)” ——《设计模式》,GoF CRP是“代码复用”的指导原则。CRP的含意 Has-a 继承 Vs 合成 实例——更好的复用性合成复用原则 合成复用原则 Favor polymorphic composition of objects over inheritance. 优先使用对象组合,而不是类继承 《设计模式:可复用面向对象软件的基础 》Has-a 关系Has-a 关系对象的合成是Has-a关系(对象组合)。class 电脑{ 主机 host=new 主机(); 显示器 monitor=new 显示器(); 光驱 cdDriver; void open(){ host.open(); monitor.open(); } 电脑对象“有一个”显示器对象,或显示器对象is-part-of电脑对象。 而电脑对象“是一个”机器,因而电脑是机器的子类(继承) 。 一般而言,Has-a与Is-a关系的差别是显著的,分别反映对象的整体-部分结构与普遍-特殊关系。实例:窗口类与矩形类实例:窗口类与矩形类窗口类“是一个”还是“有一个”矩形? Is-a关系建立在接口的一致性之上,正方形不是一个长方形! 在你拿不定主意时,合成复用原则就是指路明灯。 public class 窗口 extends 矩形{}public class 窗口 { 矩形 rect; }代码复用、委派代码复用、委派面向对象系统中功能复用的两种最常用技术是类继承和对象组合。 类继承使生成的子类复用父类的实现/代码。 对象组合使一个类复用其成员变量对象的功能。对象组合技术的关键是委派。委派/委托(delegation)使组合具有与继承同样的复用能力。public class 窗口 { 矩形 rect; void resize(){ rect.resize(); } }继承 Vs 合成继承 Vs 合成继承【这里的继承指符合LSP的非/接口继承,换言之,实现继承】复用:白箱复用(white-box reuse),父类的内部细节/实现细节对子类可见,继承关系是强耦合关系 ——父类实现中的任何变化必然会导致子类发生变化 。 如果继承下来的实现不适合解决新的问,则父类的必须被子类改写甚至重新编写父类的代码。 解决方法:只继承抽象类——任何类都不应该从具体类派生。 合成复用:黑箱复用(black-box reuse) 。被组合的对象以其接口被合成者使用,不破坏封装性。 要求更仔细地定义和设计接口。 对象的实现是基于接口写的,所以实现上存在较少的依赖关系。(DIP)。Composite Reuse Principle2Composite Reuse Principle2Favor delegation over inheritance as a reuse mechanism。 作为复用机制,委派优先于继承。Why extends is evil Why extends is evil James Gosling 作为主题演讲人,在一次Java用户组会议的Q&A[问与答]会议中,有人问他:“如果你重新发明一次Java,你会改变些什么?”, 他回答说“我会去掉类”。在笑声平息后他解释说: 真正的问题不在类自己身上,而是实现继承[implementation inheritance、 extends 关系],接口继承[Interface inheritance 、implements 关系]会更好一些。 只要有可能,你们就应该避免实现继承。You should avoid implementation inheritance whenever possible. JDK的错误JDK的错误java.util.Stack是一个java.util.Vector? stack 的特点是后进先出,且不易查找 ;Vector底层实现采用了array且线程安全 ,这与statck本身的特点不符合。 就继承而言,stack继承了父类的所有方法。但是add(int index,E element)在stack中根本就不能实现的。所以,表面上 ,Stack是Vector的扩展继承,事实上是限制/退化继承。唯一实现无用方法的合理的途径是使它抛出一个异常,因为它应该永远不被调用。 解决方法 栈常常直接使用ArrayList而不使用Stack。 设计自己的Stack。 使用JDK6.0中的Stack,泛型技术。设计Stack -1设计Stack -1class Stack{ private int stack_pointer = 0; private ArrayList the_data = new ArrayList(); public void push( Object article ){ the_data.add( stack_poniter++, article );} public Object pop(){ return the_data.remove( --stack_pointer );} public void push_many( Object[] articles ){ for( int i = 0; i < o.length; ++i ) push( articles[i] );} }Law of DemeterLaw of Demeter迪米特法则耦合的一般介绍 LoD的含意 实例1、耦合的一般介绍1、耦合的一般介绍模块——是由边界元素限定的相邻程序元素的序列,而且具有一个总体标识符代表它。边界元素一般就是{},Java中模块常常指对象和对象的方法。 我们希望模块是独立的——模块应该具有独立的功能而且与其他模块没有过多的相互作用。当然,完全不和其他模块建立相互依赖的关系是不可能的。 耦合coupling,耦合是不同模块之间相互依赖(连接、互联)程度的度量。 我们不奢求零耦合,我们追求低耦合。 低耦合低耦合DIP: 以抽象耦合为特点 ; CRP:以合成复用/松散耦合 代替强耦合的继承关系; 迪米特法则则说明,需要具体类-具体类发生耦合时,“只和自己最亲密的朋友说话,不和陌生人说话 ”。2、Law of Demeter 2、Law of Demeter Demeter,德墨特尔(迪米特) 希腊主管生产及保护婚姻的女神 迪米特法则迪米特法则Only talk to your immediate friends, Don’t talk to strangers. 只和自己最亲密的朋友说话,不和陌生人说话。 较正规的描述:Least Knowledge Principle, LKP : Each unit should have only limited knowledge about other units: only units "closely" related to the current unit. 最少知识原则:每一个单元应当对其它单元有尽可能少的了解:仅仅了解那些和当前单元有“紧密”关系的单元。一个对象应该对其他的对象有尽可能少的了解 。老子:论圣人之治 老子:论圣人之治 是以圣人之治,常使民无知无欲 。 ——最少知识原则可以降低统治成本、也可以降低耦合。 邻国相望,鸡犬之声相闻,民至老死,不相往来。 ——最大程度减少对象之间的通信。 实例:X、Y、Z实例:X、Y、Z有X、Y、Z三个类。对于X,假设只让它与Y耦合,而不与Z耦合。 public class X { private Y you = new Y(); public void method (Y y){ } }当X需要使用Z的doSth ()方法时,如何处理? public class Z{ void doSth () { System.out.println("hi"); } }1 :违反迪米特原理 方案1 :违反迪米特原理 public class X { //只让它与Y耦合 private Y yy; public void m (){ Z zero=new Z(); zero.doSomething(); } }方案2 :Y工厂方案2 :Y工厂public class Y{ public Z getZ() { return new Z();} } public class X { private Y yy = new Y(); public void m (){ yy.getZ().doSomething(); } }方案3 :Y转发消息 方案3 :Y转发消息 public class Y{ public void doSomething(){ new Z().doSomething() ; } } public class X { public void m (Y yy){ yy.doSomething(); }迪米特法则的狭义解读 迪米特法则的狭义解读 如果两个类不必彼此直接通信,则不应当相互耦合,可以通过自己最亲密的对象转发消息.最亲密的朋友: 类的成员(这是必须了解的,可能有多个亲密的成员朋友) 方法的参数对象(如yy) 方法中(不得不)创建的(局部)对象。 非最亲密的朋友,可以通过最亲密的朋友去转发消息。狭义LoD缺点狭义LoD缺点在系统里造出大量的小方法,它们仅仅是传递间接的调用,与系统的商务逻辑无关; 使一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接的关联。但会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。 倚赖关系是传递的 倚赖关系是传递的 转发消息降低了耦合,但是倚赖关系却是传递的。Z的代码变化仍然要求再次编译X。既然Y、Z的接口是一致的,可以考虑设计成类层次。依靠DIP原理,把Y设计成抽象类。 广义的迪米特法则广义的迪米特法则迪米特法则的主要用意是控制信息的过载,在将其运用到系统设计中应注意以下几点: 1) 在类的划分上,应当创建有弱耦合的类。类之间的耦合越弱,就越有利于复用。 2) 在类的结构设计上,每一个类都应当尽量降低成员的访问权限。一个类不应当public自己的属性,而应当提供取值和赋值的方法让外界间接访问自己的属性。 3) 在类的设计上,只要有可能,一个类应当设计成不变类。 4) 在对其它对象的引用上,一个类对其它对象的引用应该降到最低。不变类不变类不变对象(immutable object)是指一经创建就不可改变的对象;对应的,其所属的类称为不变类(immutable class)。 不变对象/不变类是非常吸引人的想法。除了人类对稳定的一般渴望外,不变类具有许多优点: 它容易实现和使用,不易出错,安全性更好。 在多线程编程中,不变类不需要考虑同步的问题,可以安全地共享。 它非常适合作为其他类的成员变量,不变类的稳定性保证了数据不会被改变。不变类 条件不变类 条件所有的域都是 private 。对象的域不被类外部的代码修改,是成为不变对象的最低要求。 所有的方法无副作用。副作用造成环境的变化,因此你不能够提供setter方法,杜绝其他代码直接修改域。 更一般的,不提供任何可能修改对象域的方法。如果需要操作该对象,对应的方法均返回一个新对象而保证原对象不变。 尽可能使域声明为final。对基本类型的成员变量极其有效。 如果某个域是一个引用变量,它指向的是可变对象,则不提供任何方法返回其引用。 保证没有任何一个方法会被改写。这并不要求将该类定义为final类,但是final类比较方便。 Demeter Demeter Low Coupling Principle低耦合原则,在软件工程中广为人知。低耦合原则非常general/笼统,迪米特法则希望把低耦合原则细致一下,让不必要的耦合能够一目了然。 迪米特法则最初是作为时尚规则/style rule提出的(1987 by Ian Holland ),由于许多大牛的介绍和写入籍,LoD被人们广泛接受。 Northeastern University的Karl J. Lieberherr 、 Ian Holland等围绕Demeter ideas ,目前从事Adaptive Programming (AP) and Aspect-Oriented Programming (AOP) 研究。 OOD之七大原理OOD之七大原理开放封闭原理 (The Open-Closed Principle 、OCP) 里氏代换原理 (Liskov Substitution Principle, LSP) 依赖倒转原理 (Dependence Inversion Principle, DIP) 合成复用原则 (Composite Reuse Principle, CRP) 迪米特法则 ( Law of Demeter, LoD ) 单一职责原理 (Single Responsibility Principle,SRP) 接口隔离原则 (Interface Segregation Principle, ISP) 强内聚强内聚软件设计的一条总的原则是做到强内聚、弱耦合(Strong cohesion, loose coupling或high cohesion, low coupling). 内聚是一个模块内部各成分之间相关联程度的度量 [Cohesion refers to the degree in which elements within a subsystem form a single, unified concept, with no excess elements.]。 强内聚方面的两个原理: 单一职责原则[Single Responsibility Principle,SRP] 接口隔离原则[Interface Segregation Principle、ISP] 两者都是关于内聚的原则,所以使用的例子可以通用。 它们的区别在于考虑问题的角度不同: 单一职责原则——内部变化的原因 接口隔离原则——外部用户的感受 内聚度越高, 模块越容易理解、修改和维护. Single Responsibility PrincipleSingle Responsibility Principle单一职责原理 There should never be more than one reason for a class to change. 就一个类而言,应该仅有一个引起它变化的原因 .实例:矩形系统实例:矩形系统一个GUI系统的设计。要求: 可以计算矩形的面积—— area()方法 并在屏幕上显示 —— draw()方法 几何计算系统调用Rectangle计算面积 GUI系统调用Rectangle绘制在屏幕上在编译几何计算系统时还需要编译进图形代码;需要更换显示系统时还需要重新测试所有几何计算系统…… 解决方法:将计算和绘制的职责分别放入CulRectangle和GraphRectangle中实例:调制解调器 实例:调制解调器 调制解调器就有4个功能 ,但职责却是2个:连接管理(dial and hangup)和数据通信(send and recv)。 public interface Modem{ void dialog (String pno); void hangup (); void send (char c); void recv (); }如果应用程序的变化会影响连接管理方法的签名[dialog(String pno)变成dialog (long pno)],所有使用了数据通信职责[send和recv]类却必须要重新编译。 “一个职责的变化可能会或者抑制这个类的其他职责的能力。便如你改变了一个多职责类的一个职责,你必须测试所有其他使用这个类另外的职责的程序,如果忘记这样,可能会导致不可预测的失败 ”SRP要点SRP要点一个类的职责是指引起该类变化的原因,如果一个类具有一个以上的职责,那么就会有多个不同的原因引起该类变化。 其实质就是耦合了多个互不相关的职责,就会降低这个类的内聚性。 软件设计真正要做的重要工作,就是发现职责,并把它们互相分离。 最少职责原则。最少指的是够用,单一更细。太过多的划分会造成“过度设计” 。nullInterface Segregation PrincipleInterface Segregation Principle接口隔离原则The Interface Segregation Principle (ISP): clients should not be forced to depend upon interfaces that they do not use。 不要强迫客户依赖于它们不用的接口。 一个职责常常由一系列的服务接口去表达,如果系统涉及多个职责,我们应该让接口隔离开来。 接口隔离原则2接口隔离原则2Favour many client specific interfaces over one general purpose interface 使用多个专门的接口比使用单一的总接口要好。 一个类对另一个类的依赖性,应当是建立在最小的接口之上。没有关系的接口合并在一个class/interface中,会形成一个臃肿的接口集——接口污染(Interface Contamination)解决方法-分离接口解决方法-分离接口1、利用委托分离接口。如Adapter模式 2、利用多继承分离接口。实例:能超时报警的门 实例:能超时报警的门 abstract class Door { void open(); void close(); void timeOut(); } 所有的门都需要超时报警吗 ?public abstract class Door{ abstract void open(); abstract void close(); }public interface Alarm{ void timeOut(); }AlarmDoorAlarmDoorpublic class AlarmDoor extends Door implements Alarm{ void open() { } void close() { } public void timeOut() {} } 接口与抽象类 接口与抽象类 abstract class和interface之间在对于抽象的类定义的支持方面具有很大的相似性 , 两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。 在面向对象领域,抽象类型主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类型是其中的关键所在。 语法层面 语法层面 定义 abstract class Demo interface Demo 继承 类的单继承 一个类却可以实现多个interface 一个interface继承多个接口设计理念层面 设计理念层面 abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在“is a”关系 。 interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。 如果使用interface方式来定义 Door, 我们可能没有理解清楚问题域 ,或者设计时过于随意。
/
本文档为【6最少依赖原则】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索