一、为什么要学习设计模式?
在编写软件的过程中,设计模式是为了让软件具有更好的以下优点:
代码重用性(相同功能的代码不用多次编写)
可读性(编程规范性,便于其他程序员的阅读和理解)
可扩展性(当需要增加新的功能时,非常的方便)
可靠性(当增加新的功能后,对原来的功能没有影响)
使程序呈现高内聚、低耦合的特性
二、常用的七大原则
单一职责原则
接口隔离原则
依赖倒转原则
里氏替换原则
开闭原则
迪米特法则
合成复用原则
三、单一职责原则
1、基本介绍
对类来说,一个类应该只负责一项职责。如果类A负责两个不同的职责:职责1、职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A分解为A1、A2。
这么说有点抽象,下面用代码来演示一下,化抽象为具体。
2、代码对比
代码一:
public class class01 { public static void main(String[] args) { Vehicle1 vehicle = new Vehicle1(); vehicle.run("汽车"); vehicle.run("飞机"); vehicle.run("轮船"); } } class Vehicle1 { public void run(String vehicle){ System.out.println(vehicle + "在高速上行驶"); } }
通过代码一可以看出,这样设计的结果是:飞机和轮船也是在高速上行驶,违反了单一职责原则,这显然是错误的。接下来看看代码二,与其对比一下。
代码二:
public class class02 { public static void main(String[] args) { VehicleRoad road = new VehicleRoad(); road.run("汽车"); VehicleWater water = new VehicleWater(); water.run("轮船"); } } class VehicleRoad { public void run(String vehicle) { System.out.println(vehicle + "在高速上行驶"); } } class VehicleWater { public void run(String vehicle) { System.out.println(vehicle + "在水中行驶"); } }
通过代码二,我们根据交通工具运行方法不同,分解成不同的类,解决了代码一的问题。但是有一个问题就是,这样很浪费资源,改动很大。貌似不太完美,接下来看看代码三
代码三:
public class class03 { public static void main(String[] args) { Vehicle2 vehicle = new Vehicle2(); vehicle.runRoad("汽车"); vehicle.runWater("轮船"); } } class Vehicle2{ public void runRoad(String vehicle){ System.out.println(vehicle + "在高速上行驶"); } public void runWater(String vehicle){ System.out.println(vehicle + "在水中行驶"); } }
代码三通过修改方法,与代码二比较,对原来的类没有做很大的修改,只是增加方法。这里虽然没有在类这个级别上遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责原则。
3、注意事项和使用细节
要降低类的复杂度,一个类只负责一项职责
确保提高类的可读性,可维护性
降低变更引起的风险
通常情况下,我们应当遵守单一职责原则,只有逻辑 足够简单,才可以在代码级别违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则
四、接口隔离原则
1、基本介绍
客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。
先看看一张图:
代码一:
public class class01 { public static void main(String[] args) { A a = new A(); a.method1(new B()); C c = new C(); c.method2(new D()); } } interface Interface1{ void opertion1(); void opertion2(); void opertion3(); void opertion4(); void opertion5(); } class B implements Interface1{ public void opertion1() { System.out.println("B 实现了 operation1"); } public void opertion2() { System.out.println("B 实现了 operation2"); } public void opertion3() { System.out.println("B 实现了 operation3"); } public void opertion4() { System.out.println("B 实现了 operation4"); } public void opertion5() { System.out.println("B 实现了 operation5"); } } class D implements Interface1{ public void opertion1() { System.out.println("D 实现了 operation1"); } public void opertion2() { System.out.println("D 实现了 operation2"); } public void opertion3() { System.out.println("D 实现了 operation3"); } public void opertion4() { System.out.println("D 实现了 operation4"); } public void opertion5() { System.out.println("D 实现了 operation5"); } } class A { // A 类 通过接口Interface1 依赖 B类,但只使用1、2、3方法 public void method1(Interface1 interface1){ interface1.opertion1(); } public void method2(Interface1 interface1){ interface1.opertion2(); } public void method3(Interface1 interface1){ interface1.opertion3(); } } class C { // C 类 通过接口Interface1 依赖 D类,但只使用1、4、5方法 public void method1(Interface1 interface1){ interface1.opertion1(); } public void method2(Interface1 interface1){ interface1.opertion4(); } public void method3(Interface1 interface1){ interface1.opertion5(); } }
代码一中,类A通过接口Interface1 依赖类B,类C通过接口Interface1 依赖类D,因为接口Interface1 对于类A 和类C来说不是最小接口,所以要想实现图片的功能,需要实现接口的所有方法,违反了接口隔离原则! 接下来看看代码二,与其对比一下。
代码二:
public class class02 { public static void main(String[] args) { AA aa = new AA(); aa.method1(new BB()); CC cc = new CC(); cc.method1(new DD()); } } interface Interface2{ void opertion1(); } interface Interface3{ void opertion2(); void opertion3(); } interface Interface4{ void opertion4(); void opertion5(); } class BB implements Interface2,Interface3{ public void opertion1() { System.out.println("BB 实现了operation1"); } public void opertion2() { System.out.println("BB 实现了operation2"); } public void opertion3() { System.out.println("BB 实现了operation3"); } } class DD implements Interface2,Interface4{ public void opertion1() { System.out.println("DD 实现了operation1"); } public void opertion4() { System.out.println("DD 实现了operation4"); } public void opertion5() { System.out.println("DD 实现了operation5"); } } class AA { public void method1(Interface2 interface2){ interface2.opertion1(); } public void method2(Interface3 interface3){ interface3.opertion2(); } public void method3(Interface3 interface3){ interface3.opertion3(); } } class CC { public void method1(Interface2 interface2){ interface2.opertion1(); } public void method2(Interface4 interface4){ interface4.opertion4(); } public void method3(Interface4 interface4){ interface4.opertion5(); } }
代码二的UML类图:
代码二采用了接口隔离原则。根据实际情况,把代码一中的接口Interface1拆分成三个接口,即最小接口。这样就完美的去除了类BB和类DD不用实现他们不需要的方法