设计模式是6大原则还是7大原则
设计模式应该是六大原则吧
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。
LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里
氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现
抽象化的具体步骤的规范。—— From Baidu 百科
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
什么是parmas原则,他在面向对象设计中的地位
SRP 单一职责原则就一个类而言,应该专注于做一件事和仅有一个引起它变化的原因。OCP 开放--封闭原则对于扩展开放,对于修改封闭。LSP 里氏替换原则子(继承)类能在程序中代替父类(C#:基类,Java:超类)。DIP 依赖倒置原则抽象不依赖于细节,细节应该依赖抽象。(面向抽象编程,C#为面向接口编程)。ISP 接口隔离原则接口属于用户类。(接口面用用户类,不用想着和自身层次、方法相关)REP 重用发布等价原则重用的粒度就是发布的粒度。(?这个没有具体的认识)CCP 共同封闭原则对于需求的响应,一个包中的所以类,有一个共同的响应(改变),而对于包外是不造成影响。CRP 共同重用原则包中的所有类共同重用,就是要重用就全部重用。ADP 无环依赖原则依赖关系不要存在环。ADP 稳定依赖原则朝着稳定的方向进行依赖。SAP 稳定抽象原则包的抽象程度应该和稳定程序一致。
里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的五大原则之一,它是由计算机科学家芭芭拉·利斯科夫提出的。该原则规定,所有引用父类对象的地方,都可以顺利地使用其子类的对象代替,而不会出现程序错误或异常。换言之,若一个类的方法使用父类作为参数,那么它的子类也应该能够被传递到该方法中,而且不应该对该方法的行为产生任何影响。此外,子类还应该可以在不改变父类方法的前提下,扩展或重写父类的方法。这个原则的主要目的是确保类的扩展性和灵活性,同时降低代码的耦合度。如果不遵守LSP,就会导致代码臃肿、冗长,难以维护和扩展。 LSP有三个重要的条件:1.子类必须完全实现父类的方法。这意味着,子类不能删除任何父类的方法,也不能改变它们的行为。2.子类可以有自己的方法。子类可以拥有自己的方法,但不能改变父类的方法。3.子类可以有自己的属性。 子类可以拥有自己的属性,但它们必须与父类相同或更具体。 举个例子,如果我们有一个Animal类和一个Dog类,Dog类是Animal类的子类。Animal类有一个makeSound()方法,而Dog类扩展了该方法,它可以不仅可以发出动物的声音,还可以摇尾巴。在这种情况下,Dog类遵循了LSP。另一个例子是Shape类和Rectangle类。Shape类是一个抽象类,定义了一个计算面积的方法。Rectangle类继承自Shape类,并实现了计算矩形面积的方法。在这种情况下,Rectangle类仍然遵循了LSP,因为它扩展了Shape类的功能,没有修改原有的行为。总之,LSP需要我们在设计类时注重代码的可维护性、可扩展性和可重用性,避免重复代码和不必要的代码耦合。只有遵循LSP原则,才能更好地实现面向对象设计的目标,提高代码质量和开发效率。
里氏替换原则的形象理解
我们来研究一下LSP的实质。学习OO的时候,我们知道,一个对象是一组状态和一系列行为的组合体。状态是对象的内在特性,行为是对象的外在特性。LSP所表述的就是在同一个继承体系中的对象应该有共同的行为特征。这一点上,表明了OO的继承与日常生活中的继承的本质区别。举一个例子:生物学的分类体系中把企鹅归属为鸟类。我们模仿这个体系,设计出这样的类和关系。类“鸟”中有个方法fly,企鹅自然也继承了这个方法,可是企鹅不能飞阿,于是,我们在企鹅的类中覆盖了fly方法,告诉方法的调用者:企鹅是不会飞的。这完全符合常理。但是,这违反了LSP,企鹅是鸟的子类,可是企鹅却不能飞!需要注意的是,此处的“鸟”已经不再是生物学中的鸟了,它是软件中的一个类、一个抽象。有人会说,企鹅不能飞很正常啊,而且这样编写代码也能正常编译,只要在使用这个类的客户代码中加一句判断就行了。但是,这就是问题所在!首先,客户代码和“企鹅”的代码很有可能不是同时设计的,在当今软件外包一层又一层的开发模式下,你甚至根本不知道两个模块的原产地是哪里,也就谈不上去修改客户代码了。客户程序很可能是遗留系统的一部分,很可能已经不再维护,如果因为设计出这么一个“企鹅”而导致必须修改客户代码,谁应该承担这部分责任呢?(大概是上帝吧,谁叫他让“企鹅”不能飞的。^_^)“修改客户代码”直接违反了OCP,这就是OCP的重要性。违反LSP将使既有的设计不能封闭!修正后的设计如下:但是,这就是LSP的全部了么?书中给了一个经典的例子,这又是一个不符合常理的例子:正方形不是一个长方形。这个悖论的详细内容能在网上找到,我就不多废话了。LSP并没有提供解决这个问题的方案,而只是提出了这么一个问题。于是,工程师们开始关注如何确保对象的行为。1988年,B. Meyer提出了Design by Contract(契约式设计)理论。DbC从形式化方法中借鉴了一套确保对象行为和自身状态的方法,其基本概念很简单:Pre-condition:每个方法调用之前,该方法应该校验传入参数的正确性,只有正确才能执行该方法,否则认为调用方违反契约,不予执行。这称为前置条件(Pre-condition)。Post-Condition:一旦通过前置条件的校验,方法必须执行,并且必须确保执行结果符合契约,这称之为后置条件(Post-condition)。Invariant:对象本身有一套对自身状态进行校验的检查条件,以确保该对象的本质不发生改变,这称之为不变式(Invariant)。以上是单个对象的约束条件。为了满足LSP,当存在继承关系时,子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松;而子类中方法的后置条件必须与超类中被覆盖的方法的后置条件相同或者更为严格一些OO语言中的特性能够说明这一问题:继承并且覆盖超类方法的时候,子类中的方法的可见性必须等于或者大于超类中的方法的可见性,子类中的方法所抛出的受检异常只能是超类中对应方法所抛出的受检异常的子类。public class SuperClass{public void methodA() throws Exception{}}public class SubClassA extends SuperClass{//this overriding is illegal.private void methodA() throws IOException{}}public class SubClassB extends SuperClass{//this overriding is OK.public void methodA() throws FileNotFoundException{}}从Java5开始,子类中的方法的返回值也可以是对应的超类方法的返回值的子类。这叫做“协变”(Covariant)public class SuperClass {public Number caculate(){return null;}}public class SubClass extends SuperClass{//only compiles in Java 5 or later.public Integer caculate(){return null;}}可以看出,以上这些特性都非常好地遵循了LSP。但是DbC呢?很遗憾,主流的面向对象语言(不论是动态语言还是静态语言)还没有加入对DbC的支持。但是随着AOP概念的产生,相信不久DbC也将成为OO语言的一个重要特性之一。一些题外话:前一阵子《敲响OO时代的丧钟》和《丧钟为谁而鸣》两篇文章引来了无数议论。其中提到了不少OO语言的不足。事实上,遵从LSP和OCP,不管是静态类型还是动态类型系统,只要是OO的设计,就应该对对象的行为有严格的约束。这个约束并不仅仅体现在方法签名上,而是这个具体行为的本身。这才是LSP和DbC的真谛。从这一点来说并不能说明“万事万物皆对象”的动态语言和“C++,Java”这种“按接口编程”语言的优劣,两类语言都有待于改进。庄兄对DJ的设想倒是开始引入DbC的概念了。这一点还是非常值得期待的。^_^另外,接口的语义正被OCP、LSP、DbC这样的概念不断地强化,接口表达了对象行为之间的“契约”关系。而不是简单地作为一种实现多继承的语法糖。
什么是里氏替换原则
里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
如此,问题产生了:“我们如何去度量继承关系的质量?”
Liskov于1987年提出了一个关于继承的原则“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“继承必须确保超类所拥有的性质在子类中仍然成立。”也就是说,当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系。
该原则称为Liskov Substitution Principle——里氏替换原则。
里氏代换原则的示例
LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。如果两个具体的类A,B之间的关系违反了LSP的设计,(假设是从B到A的继承关系)那么根据具体的情况可以在下面的两种重构方案中选择一种。-----创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。-----从B到A的继承关系改为委派关系。