设计模式原则
1 2 3 4 5 6 7
| 1、单一职责 2、开闭原则 3、接口隔离 4、里氏替换 5、依赖倒转 6、合成复用 7、迪米特法则
|
单一职责
对类来说,即一个类只负责一项职责
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Vehicle { public void run(String vehicleName) { System.out.println(vehicleName + "在陆地上运行"); }; }
class Test { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.run("汽车"); vehicle.run("飞机"); } } 此方式违反了单一职责原则,Vehicle并不是只是单一的职责。并且如果我要对飞机进行特别修改的话,就会对汽车造成影响。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class AirVehicle { public void run(String vehicleName) { System.out.println(vehicleName + "在天上运行"); }; }
class CarVehicle { public void run(String vehicleName) { System.out.println(vehicleName + "在陆地上运行"); }; }
class Test { public static void main(String[] args) { AirVehicle vehicle = new AirVehicle(); vehicle.run("汽车"); vehicle.run("飞机"); } } 👆正确方式,或者如果类中职责足够简单的话,可以降级到方法的单一职责👇 public class Vehicle { public void carRun(String vehicleName) { System.out.println(vehicleName + "在地上运行"); }; public void AirRun(String vehicleName) { System.out.println(vehicleName + "在天上运行"); }; }
class Test { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.carRun("汽车"); vehicle.AirRun("飞机"); } }
|
接口隔离
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上

错误方式👆 上述违反了接口隔离,C、D类会把Interface中所有的方法都会实现,但是A、B类并不是会依赖Interface所有的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| interface Interface { void operation_1(); void operation_2(); void operation_3(); void operation_4(); void operation_5(); }
class C implements Interface{
@Override public void operation_1() {
}
@Override public void operation_2() {
}
@Override public void operation_3() {
}
@Override public void operation_4() {
}
@Override public void operation_5() {
} }
class D implements Interface{
@Override public void operation_1() {
}
@Override public void operation_2() {
}
@Override public void operation_3() {
}
@Override public void operation_4() {
}
@Override public void operation_5() {
} }
class A { public void op(Interface i) { i.operation_1(); i.operation_2(); i.operation_3(); } }
class B { public void op(Interface i) { i.operation_1(); i.operation_2(); i.operation_4(); i.operation_5(); } }
|

正确方式👆,C、D仅实现A,B依赖所需
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| interface Interface_1 { void operation_1();
void operation_2(); }
interface Interface_2 { void operation_3(); }
interface Interface_3 {
void operation_4();
void operation_5(); }
class C implements Interface_1, Interface_2 {
@Override public void operation_1() {
}
@Override public void operation_2() {
}
@Override public void operation_3() {
} }
class D implements Interface_1, Interface_3 {
@Override public void operation_1() {
}
@Override public void operation_2() {
}
@Override public void operation_4() {
}
@Override public void operation_5() {
} }
class A { public void op(Interface_1 interface1, Interface_2 interface2) { interface1.operation_1(); interface1.operation_2(); interface2.operation_3(); } }
class B { public void op(Interface_1 interface1, Interface_3 interface3) { interface1.operation_1(); interface1.operation_2(); interface3.operation_4(); interface3.operation_5(); } }
|
依赖倒转原则
1、高层模块不应该依赖底层模块,二者都应该依赖器抽象
2、抽象不应该依赖细节,细节应该依赖抽象
3、依赖倒转的中心思想是面向接口编程
4、依赖倒转原则是基于这样的设计理念,相对于细节的多变性,抽象的东西要稳定的多,以抽象为基础比细节为基础的架构要稳定的多
5、使用接口或者抽象类的目的是制定好规范,而不涉及到具体的操作,具体的操作应交给实现类
6、有三种传递方式:接口、setter、构造器
1 2 3 4 5 6 7 8 9 10 11
| class Email { public String getInfo() { return "邮件"; } }
class Person { public void getMessage(Email email) { System.out.println(email.getInfo()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Email implements Receiver{ public String getInfo() { return "邮件信息"; } }
class Wechat implements Receiver{ public String getInfo() { return "微信信息"; } }
interface Receiver { String getInfo(); }
class Person { public void getMessage(Receiver receiver) { System.out.println(receiver.getInfo()); } }
|
里氏替换
1、所有引用基类的地方必须能透明地使用其子类的对象
2、在子类中尽量不要重写父类的方法
3、可以通过聚合、组合、依赖来决绝问题

1 2 3 4 5 6 7 8 9 10
| class A { public void run() {}; }
class B extends A { @Override public void run() { System.out.println("重写A类run, 继承就没意义了"); } }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Base { }
class A extends Base{ public void run() { System.out.println("A类的run"); }; }
class B extends Base { private A a = new A(); public void run() { System.out.println("B类的run"); } public void runWithA() { a.run(); } }
|
开闭原则
1、对提供方扩展开放,对使用方修改关闭;用抽象扩展框架,用实现扩展细节
2、软件变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化
上方依赖倒转例子满足开闭原则
迪米特法则
1、一个对象应该对其他对象保持最少的了解
2、类与类的关系越密切,耦合度越大
3、迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。不管被依赖的类多么复杂,都尽量将逻辑封装在类的内部,对外提供public方法,不对外泄露任何信息。
对非直接朋友的耦合:非直接朋友(局部变量)
错误方式👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| public class Test { public static void main(String[] args) { SchoolManager schoolManager = new SchoolManager(); schoolManager.PRINTaLLEmployee(new CollegeManager()); } }
class Employee { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } }
class CollegeEmployee { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } }
class CollegeManager{ public List<CollegeEmployee> getAllEmployee(){ List<CollegeEmployee> list = new ArrayList<CollegeEmployee>(); for (int i = 0; i < 10; i++) { CollegeEmployee emp = new CollegeEmployee(); emp.setId("学院员工ID="+i); list.add(emp); } return list; } }
class SchoolManager{ public List<Employee> getAllEmployee(){ List<Employee>list = new ArrayList<Employee>(); for (int i = 0; i < 5; i++) { Employee emp = new Employee(); emp.setId("学校总部员工ID="+i); list.add(emp); } return list; } void PRINTaLLEmployee(CollegeManager sub){ List<CollegeEmployee>list1 = sub.getAllEmployee(); System.out.println("===========学院员工=============="); for (CollegeEmployee e :list1) { System.out.println(e.getId()); } List<Employee>list2 = this.getAllEmployee(); System.out.println("===========学院总部员工=============="); for (Employee e :list2) { System.out.println(e.getId()); } } }
|
正确👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| public class Test { public static void main(String[] args) { SchoolManager schoolManager = new SchoolManager(); schoolManager.printAllEmployee(new CollegeManager()); } }
class Employee { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } }
class CollegeEmployee { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } }
class CollegeManager{ public List<CollegeEmployee> getAllEmployee(){ List<CollegeEmployee> list = new ArrayList<CollegeEmployee>(); for (int i = 0; i < 10; i++) { CollegeEmployee emp = new CollegeEmployee(); emp.setId("学院员工ID="+i); list.add(emp); } return list; } public void printEmployee(){ List<CollegeEmployee>list1 = getAllEmployee(); System.out.println("===========学院员工=============="); for (CollegeEmployee e :list1) { System.out.println(e.getId()); } } }
class SchoolManager{ public List<Employee> getAllEmployee(){ List<Employee>list = new ArrayList<Employee>(); for (int i = 0; i < 5; i++) { Employee emp = new Employee(); emp.setId("学校总部员工ID="+i); list.add(emp); } return list; } void printAllEmployee(CollegeManager sub){ sub.printEmployee();
List<Employee>list2 = this.getAllEmployee(); System.out.println("===========学院总部员工=============="); for (Employee e :list2) { System.out.println(e.getId()); } } }
|
合成复用
1、尽量使用聚合和组合,而不是继承
原则总结:
1、找出应用中需要变化之外,把他们独立出来,不要和那些不需要变化的代码混在一起
2、针对接口编程,而不是针对实现编程
3、为了交互对象之间的松耦合设计而努力