- OPC(Open-Closed Principle 开-闭原则)
一个软件实体应当对扩展开放,对修改关闭。也就是说在设计一个模块的时候应当使这个模块可以在不被修改的前提下被扩展。
- LSP(Liskov Substitution Principle 里氏代换原则)
任何基类可以出现的地方子类一定可以出现。
里氏代换原则的严格表达式:
如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。
里氏代换原则是继承复用的基石。只有当衍生类可以替换掉基类,软件单位的功能不会受到影响时,基类才能真正被复用,而衍生类也才能够在基类的基础上增加新的行为。
- DIP(Dependency Inversion Principle 依赖倒转原则)
要依赖于抽象,不要依赖于实现。
依赖关系的种类:
1.零耦合关系;
2.具体耦合关系;
3.抽象耦合关系。
依赖倒转原则要求客户端依赖于抽象耦合。依赖倒转的表述如下:
抽象不应当依赖于细节;细节应当依赖于抽象。也就是说,要针对接口编程,不要针对实现编程。
保证这一点,一个具体的Java类应当只实现Java接口和抽象Java类中声明过的方法,而不应当给出多余的方法。
- ISP(Interface Segregation Principle 接口隔离原则)
应该为客户端提供尽可能小的单独接口,而不要提供大的总接口。
每一个Java接口都应该仅仅把客户端需要的行为暴露给客户端,而没有将客户端所不需要的行为放在接口中。准确而恰当地划分角色以及角色所对应的接口,是面向对象的设计的一个重要的组成部分。将没有关系的接口合并在一起,形成一个臃肿的大接口,是对角色和接口的污染。
- CARP(Compositon/Aggregation Principle 组合/聚合复用原则)
要尽可能使用合成/聚合,而不是继承关系达到复用的目的。
合成:has-a的一种,表示组成部分,如一个人有手,有眼。
聚合:has-a的一种,表示拥有,如一个人可以有房,有车。
继承:is-a的一种,表示属于某一类,如男人是人类的一个子类。
合成/聚合复用的优点:
新对象存取成分对象的唯一方法是通过成分对象的接口。
这种复用是黑箱复用。因为成分对象的细节是新对象看不见的。
这种复用支持包装。
这种复用所需依赖较少。
每一个新类可以将焦点聚集在一个任务上。
这种复用可以在运行时间内动态进行,新对象可以动态地引用与成分对象类型相同的对象。
缺点:
使用这种复用建造的系统会有较多的对象需要管理。
继承复用的优点:
新的实现较为容易,因为超类的大部分功能可以通过继承关系自动进入子类。
修改或扩展继承而来的实现较为容易。
缺点:
继承复用破坏包装,将超类的实现细节暴露给子类。
如果超类的实现发生变化,那么子类的实现也不得不发生变化。
从超类结成而来的实现是静态的,不可能在运行时间内发生改变,因此没有足够的灵活性。
- LoD(Law of Demeter 迪米特法则)
一个软件实体应当与尽可能少的与其他软件实体发生相互作用。
描述:如果某人和朋友都需要与陌生人发生相互作用,那么迪米特法则建议某人不要直接与陌生人发生相互作用,而是通过朋友与陌生人直接发生作用。
确定当前对象的朋友:
当前对象本身;
以参量形式传入当前对象方法中的对象;
当前对象的实例变量直接引用的对象;
当前对象的实例变量如果是一个集合,那么集合中的元素都是朋友;
当前对象所创建的对象。
以上内容出自《Java与模式》一书。可以把这些规则看成是Java设计模式的基石,当然要理解Java的设计模式,理解这些规则是前提。当然,高质量的设计也离不开这些规则。