概括:
原则 |
含义 |
具体方法 |
开闭原则 |
对扩展开放,对修改关闭 |
多使用抽象类和接口 |
里氏代换原则 |
基类可以被子类替换 |
使用抽象类继承,不使用具体类继承 |
依赖倒转原则 |
要依赖于抽象,不要依赖于具体 |
针对接口编程,不针对实现编程 |
接口隔离原则 |
使用多个隔离的接口,比使用单个接口好 |
建立最小的接口 |
迪米特法则 |
一个软件实体淫荡尽可能少地与其他实体发生相互作用 |
通过中间类建立联系 |
合成复用原则 |
尽量使用合成/聚合,而不是使用继承 |
尽量使用合成/聚合,而不是使用继承 |
一.开闭原则:
一句话概括:对扩展开放,对修改关闭.
为什么要遵循开闭原则:
软件开发完的代码需要经过多种测试才能够投入使用,如果对原来的代码进行了修改,并不能保证软件的其他功能还是依旧好使,需要重新对代码进行全面的测试,有些改动需要对原来的代码做大规模的改动甚至重新构造系统.
解决方法:多使用抽象类和接口.
二.里氏代换原则
一句话概括:子类必须能够替换成它们的基类
更加详细的解释:在一个软件系统中,子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作.子类也能够在基类的基础上增加新的行为.
里氏代换是对开闭原则的补充,他讲的是基类和子类的关系.只有当这种关系存在时,里氏代换关系才存在.
长方形与正方形的例子:
如果按左图的来看,长方形求面积与正方形求面积的方法显然是不一样的,(假设这里正方形面积为 ((width+height)/2)^2 ),那就不符合里氏替换了.
按照右图则符合.
由此可见,在进行设计的时候,我们应该尽量从抽象类继承,而不是从具体类继承.如果从继承等树来看,所有叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口.当然这只是一个一般性的指导原则,使用的时候还要具体情况具体分析.
三.依赖倒转原则
一句话概括:要依赖于抽象,不要依赖于具体
依赖也就是耦合,分为三种:
1.零耦合(Nil Couping)关系:两个类没有依赖关系,(基本上就是这2个类没有互相调用的关系,甚至是没有关系)
2.具体耦合(Concrete Couping)关系:两个具体的类之间有依赖关系,如果一个类直接引用另一个具体类,就是这种关系.(也就是我们最早写的代码,直接自己new对象)
3.抽象耦合(Abstract Couping)关系:这种关系发生在一个具体类和一个抽象类之间,这样就使必须发生关系的类之间保持最大的灵活性.(在Action中调用Service,这个必须是有关系的,所以我们在做的时候使用接口,利用spring这个工厂来自动注入)
要做到依赖倒转原则,使用抽象方式耦合是关键(必须耦合的地方,那就用接口).由于一个抽象耦合总要涉及具体类从抽象类继承,并且需要保证在任何引用到某类的地方都可以改换成其他子类,因此里氏代换是依赖倒转原则的基础,依赖倒转原则是OOD的核心原则,设计模式的研究和应用都是他作为指导原则的.
四.接口隔离原则
一句话概括:使用多个隔离的接口,比使用单个接口好.
举个String的例子来看,左边的是不符合接口隔离的,右边的是符合的:
五.迪米特法则(最少知道原则)
一句话概括:talk only to your immediate friends.
一个类少去了解其他类的内部.减少耦合.
六.合成复用原则
一句话概括:尽量使用聚合/组合,少使用继承
使用继承和组合/聚合的目的是为了复用
什么时候使用继承,必须满足以下所有的条件:
1.子类是超类的一个特殊种类,而不是超类的一个角色,也就是区分"Has -a " 与 " is -a" .
2.永远不会出现需要将子类换成另外一个子类的情况.如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承.
3.子类具有扩展超类的责任,而不是具有置换掉(override)或注销掉(Nullify)超类的责任,如果一个子类需要大量的置换掉超类的行为,那么这个类就不应该是这个超类的子类.
4.只有在分类学角度上有意义时,才可以使用继承.不要从工具类继承.
专题设计模式有关的内容参考自:Java高手真经系列-JavaWeb系统设计与架构