设计模式全文
七大原则
- 设计模式的依据
- 核心思想
- 找出应用中可能需要变化的地方,将它们独立出来,不和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 为了交互对象之间的
松耦合
单一职责原则
- Single Responsibility Principle
- 对类来说,一个类只负责一项原则
- 体现各行其职
- 降低类的复杂度,达到一个类只负责一项职责,降低变更带来的风险
- 类中代码比较少,也可以在方法级别上遵守单一原则
- 交通工具的运行案例
类上遵守
class RoadVehicle {
public void run(String vehicle) {
System.out.println(vehicle + " is run in the road...");
}
}
class SkyVehicle {
public void run(String vehicle) {
System.out.println(vehicle + " is run in the sky...");
}
}
class SeaVehicle {
public void run(String vehicle) {
System.out.println(vehicle + " is run in the sea...");
}
}
方法上遵守
class VehicleSR {
public void runRoad(String vehicle) {
System.out.println(vehicle + " is run in the road...");
}
public void runSky(String vehicle) {
System.out.println(vehicle + " is run in the sky...");
}
public void runSea(String vehicle) {
System.out.println(vehicle + " is run in the sea...");
}
}
接口隔离原则
- Interface Segregation Principle
- 客户端不应该依赖他不需要的接口,即一个类对另一个类的依赖,应该建立在
最小的接口上 - 一个类所依赖的类,要求是使用到该类所实现的对象的所有方法,没有方法是实现了,却用不到的
- 案例,B和D多实现了几个方法,
要将Interface1拆成两个接口,让A和C与需要的接口建立以来即可 - 接口隔离处理
依赖倒转(倒置)原则
- Dependence Inversion Principle
- 高层模块不应该依赖底层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 面向接口编程
- 抽象的东西要稳定
- 抽象类制定好规范,不涉及具体的操作,展现细节的任务交给实现类完成
- 为使用层和实际资源增加一个缓冲层,增加可扩展性,扩展时,先修改底层资源(接口);使用层依赖于接口,可以不断优化具体实现
- 使用类
Person依赖接口,并不直接依赖实现类
interface IReceiver {
String getInfo();
}
class Email implements IReceiver {
public String getInfo() {
return "hello, world";
}
}
class Wechat implements IReceiver {
public String getInfo() {
return "weChat";
}
}
class Person {
public void receive(IReceiver iReceiver) {
System.out.println(iReceiver.getInfo());
}
}
传递的三种方式
- 接口传递
- 构造传递
class Person {
IReceiver ir;
public Person(IReceiver ir) {
this.ir = ir;
}
public void receive() {
System.out.println(ir.getInfo());
}
}
//使用
Person person = new Person(new Email());
person.receive();
- setter传递
interface IPerson {
void receive();
void setIr(IReceiver ir);
}
interface IReceiver {
String getInfo();
}
class Email implements IReceiver {
public String getInfo() {
return "hello, world";
}
}
class Wechat implements IReceiver {
public String getInfo() {
return "weChat";
}
}
class Person implements IPerson {
IReceiver ir;
public void receive() {
System.out.println(ir.getInfo());
}
public void setIr(IReceiver ir) {
this.ir = ir;
}
}
//使用
Person person = new Person();
person.setIr(new Wechat());
person.receive();
注意事项
- 低层模块尽量都要有抽象类或接口,稳定性更好
- 变量的声明类型尽量是抽象类或接口,在实际的变量引用和实际对象间,存在一个缓冲层,利于程序拓展和优化
- 继承时要遵循里氏替换原则
里氏替换原则
- Likov Substitution Principle
- 父类中凡是已经实现好的方法,实际上是设定规范和契约,虽然不强制所有子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,那么就会对整个继承体系造成破环
- 继承存在弊端,使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他类所继承,当这个类修改时,必须考虑所有子类
- 继承的原则
- 如果对每个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换成O2时,程序P的行为没有发生改变,那么T2是T1的子类型
- 所有引用基类的地方必须能透明地使用其子类对象
- 子类中
尽量不要重写父类方法,如果子类大面积地重写了父类的方法,那么就没有继承的必要了- 继承让两个类耦合增强了,适当情况下,可以通过
聚合、组合、依赖来解决问题
- B类需要重写A的方法,可以将AB提出一个基类,让B与A组合
开闭原则ocp
- Open Closed Principle,核心,基础,重要
- 类、模块和函数应该对扩展(
对提供功能方)开放,对修改(对使用方)关闭,用抽象构建框架,用实现扩展细节 - 当软件需要变化时,通过
扩展软件实体的行为来实现变化,不通过修改已有的代码 - 强调代码的拓展性,如果需要增加一个绘画形状,只需要新增一个图形继承
Shape
//使用方依赖抽象,尽量简单
class GraphicEditor {
public void draw (Shape s) {
s.draw();
}
}
abstract class Shape {
int m_type;
abstract void draw();
}
class Rectangle extends Shape {
Rectangle() {
super.m_type = 1;
}
void draw() {
System.out.println("矩形");
}
}
class Circle extends Shape {
Circle() {
super.m_type = 2;
}
void draw() {
System.out.println("圆形");
}
}
class Triangle extends Shape {
Triangle() {
super.m_type = 3;
}
void draw() {
System.out.println("三角形");
}
}
迪米特法则
- Demeter Principle,最少知道原则,只与直接的朋友通信
- 直接的朋友,每个对象都会其他对象有耦合关系,只要两个对象之间有耦合关系,那么就是朋友关系,
依赖、关联、组合和聚合等- 其中出现的成员变量,方法参数,方法返回值中的类为直接的朋友,而局部变量中的类不是直接朋友
- 陌生的类,最好不要以局部变量的形式出现
- 一个对象应该对其他对象保持最少的了解
- 类与类关系越密切,耦合度越大
- 一个类对自己依赖的类知道的越少越好,不管被依赖的类多复杂,都将逻辑分装在类的内部,对外只提供构造方法
- 一个类的行为要在本类中实现,不要再其他类中实现
细节
- 核心是降低类与类之间的耦合
- 每个类都减少了不必要的依赖,只是要求降低类之间的耦合关系,并不是完全没有依赖
合成复用原则
- Composite Reuse Principle
- 尽量使用
合成/聚合的方式,而不使用继承 - 如果只是为了让B类使用A类的方法,而让B去
继承A,会让AB的耦合性增强 - 要倾向于
has a,避免is a