1.设计模式的七大原则
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
- 里氏替换原则
- 开闭原则-ocp (工厂模式用到了这个)
- 迪米特法则
- 合成复用原则
1.1单一职责原则
-
概念:对类来说:一个类应该只负责一个职责。
如果A负责两个职责,A1.A2,为了避免职责A1发生变更后,影响职责A2的执行,需要把A进行粒度分解,分为A1,A2
-
优势及注意事项:
1.降低类的复杂度
2.提高程序的可读性、可维护性
3.降低变更引起的风险
4.遵守设计的单一原则
-
上代码
public class SingleResponsibility { public static void main(String[] args) { // TODO Auto-generated method stub RoadVehicle roadVehicle = new RoadVehicle(); roadVehicle.run("摩托车"); roadVehicle.run("汽车"); AirVehicle airVehicle = new AirVehicle(); airVehicle.run("飞机"); WaterVehicle waterVehicle = new WaterVehicle(); waterVehicle.run("游轮"); } } //1. 遵守单一职责原则,即一个类负责一个职责。 //2. 但是这样做的改动较大,即将类分解,同时修改客户端 //3. 思考改进:直接修改Vehicle 类,里边直接加这3个实现的方法,改动的代码会比较少。 class RoadVehicle { public void run(String vehicle) { System.out.println(vehicle + "在公路运行"); } } class AirVehicle { public void run(String vehicle) { System.out.println(vehicle + "在天空运行"); } } class WaterVehicle { public void run(String vehicle) { System.out.println(vehicle + "在水中运行"); } }
1.2接口隔离原则
-
概念:
理解:接口隔离—一个类依赖另一个类通常是通过一个接口来完成。
-
上代码
public class Segregation1 { public static void main(String[] args) { // TODO Auto-generated method stub // 使用一把 A a = new A(); a.depend1(new B()); // A类通过接口去依赖B类 a.depend2(new B()); a.depend3(new B()); C c = new C(); c.depend1(new D()); // C类通过接口去依赖(使用)D类 c.depend4(new D()); c.depend5(new D()); } } // 接口1 interface Interface1 { void operation1(); } // 接口2 interface Interface2 { void operation2(); void operation3(); } // 接口3 interface Interface3 { void operation4(); void operation5(); } class B implements Interface1, Interface2 { public void operation1() { System.out.println("B 实现了 operation1"); } public void operation2() { System.out.println("B 实现了 operation2"); } public void operation3() { System.out.println("B 实现了 operation3"); } } class D implements Interface1, Interface3 { public void operation1() { System.out.println("D 实现了 operation1"); } public void operation4() { System.out.println("D 实现了 operation4"); } public void operation5() { System.out.println("D 实现了 operation5"); } } class A { // A 类通过接口Interface1,Interface2 依赖(使用) B类,但是只会用到1,2,3方法 public void depend1(Interface1 i) { i.operation1(); } public void depend2(Interface2 i) { i.operation2(); } public void depend3(Interface2 i) { i.operation3(); } } class C { // C 类通过接口Interface1,Interface3 依赖(使用) D类,但是只会用到1,4,5方法 public void depend1(Interface1 i) { i.operation1(); } public void depend4(Interface3 i) { i.operation4(); } public void depend5(Interface3 i) { i.operation5(); } }
1.3依赖倒转原则
-
基本介绍
重点:
它的中心思想是:面向接口编程
抽象不依赖细节,细节依赖抽象
接口和抽象类的目的是:指定规范
-
注意事项
-
底层模块尽量都要有抽象类或接口。
-
变量的声明尽量是一个接口,
举例:加入一个类A继承了接口B,写一个Object obj = new A(); 其实这样的话,obj是直接与接口B有交接,等于是通过B来联系类A,这样中间就会有一个缓冲,接口B就是这个缓冲,
-
-
依赖传递的方式:
- 接口传递
- 构造方法传递
- setter方法传递
public class DependecyInversion {
public static void main(String[] args) {
//客户端无需改变
Person person = new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
//定义接口
interface IReceiver {
public String getInfo();
}
class Email implements IReceiver {
public String getInfo() {
return "电子邮件信息: hello,world";
}
}
//增加微信
class WeiXin implements IReceiver {
public String getInfo() {
return "微信信息: hello,ok";
}
}
//方式2
class Person {
//这里我们是对接口的依赖
public void receive(IReceiver receiver ) {
System.out.println(receiver.getInfo());
}
}
1.4里氏替换原则
-
基本介绍:
- 它是一个麻省理工的一个姓里的女士提出来的。
- 它要求我们尽量的不要改写我们的父类的方法。(不要重写父类方法)
- 如果重写了,可以通过聚合、组合、依赖来解决问题。
-
目的:
就是保证父类的方法不被覆盖
-
上代码
public class Liskov { public static void main(String[] args) { // TODO Auto-generated method stub A a = new A(); System.out.println("11-3=" + a.func1(11, 3)); System.out.println("1-8=" + a.func1(1, 8)); System.out.println("-----------------------"); B b = new B(); //因为B类不再继承A类,因此调用者,不会再func1是求减法 //调用完成的功能就会很明确 System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3 System.out.println("1+8=" + b.func1(1, 8));// 1+8 System.out.println("11+3+9=" + b.func2(11, 3)); //使用组合仍然可以使用到A类相关方法 System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3 } } //创建一个更加基础的基类 class Base { //把更加基础的方法和成员写到Base类 } // A类 class A extends Base { // 返回两个数的差 public int func1(int num1, int num2) { return num1 - num2; } } // B类继承了A // 增加了一个新功能:完成两个数相加,然后和9求和 class B extends Base { //如果B需要使用A类的方法,使用组合关系 private A a = new A(); //这里,重写了A类的方法, 可能是无意识 public int func1(int a, int b) { return a + b; } public int func2(int a, int b) { return func1(a, b) + 9; } //我们仍然想使用A的方法 public int func3(int a, int b) { return this.a.func1(a, b); } }
1.5开闭原则(ocp原则—open close principle)
-
基本介绍:
-
开闭原则是编程中最基础最重要的原则
-
对扩展开放,对修改关闭:——可以是用抽象创建框架,用实现来扩展细节。
咂一看这句话有矛盾,我们来理解一下这句话:
扩展开放——对提供者开放(可以理解为开发人员);
修改关闭——对使用者关闭(可以理解为原先使用方的这边并没有修改)
-
添加修改功能的时候尽量是扩展,不要进行修改。
-
-
方式1 的优缺点
1)优点是比较好理解,简单易操作。
2)缺点是违反了设计模式的 ocp 原则,即 对扩展开放 (提供方 ),对修改关闭 使用方 。 即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
3)比如我们这时要新增加一个图形种类三角形 ,我们需要做如下修改的地方较多
4)代码演示public class Ocp { public static void main(String[] args) { //使用看看存在的问题 GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Triangle()); } } //这是一个用于绘图的类 [使用方] class GraphicEditor { //接收Shape对象,然后根据type,来绘制不同的图形 public void drawShape(Shape s) { if (s.m_type == 1) drawRectangle(s); else if (s.m_type == 2) drawCircle(s); else if (s.m_type == 3) drawTriangle(s); } //绘制矩形 public void drawRectangle(Shape r) { System.out.println(" 绘制矩形 "); } //绘制圆形 public void drawCircle(Shape r) { System.out.println(" 绘制圆形 "); } //绘制三角形 public void drawTriangle(Shape r) { System.out.println(" 绘制三角形 "); } } //Shape类,基类 class Shape { int m_type; } class Rectangle extends Shape { Rectangle() { super.m_type = 1; } } class Circle extends Shape { Circle() { super.m_type = 2; } } //新增画三角形 class Triangle extends Shape { Triangle() { super.m_type = 3; } }
方 式 2 的设计方案 : 定 义一个 Shape 抽象
上代码:
public class Ocp { public static void main(String[] args) { //使用看看存在的问题 GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Triangle()); graphicEditor.drawShape(new OtherGraphic()); } } //这是一个用于绘图的类 [使用方] class GraphicEditor { //接收Shape对象,调用draw方法 public void drawShape(Shape s) { s.draw(); } } //Shape类,基类 abstract class Shape { int m_type; public abstract void draw();//抽象方法 } class Rectangle extends Shape { Rectangle() { super.m_type = 1; } @Override public void draw() { // TODO Auto-generated method stub System.out.println(" 绘制矩形 "); } } class Circle extends Shape { Circle() { super.m_type = 2; } @Override public void draw() { // TODO Auto-generated method stub System.out.println(" 绘制圆形 "); } } //新增画三角形 class Triangle extends Shape { Triangle() { super.m_type = 3; } @Override public void draw() { // TODO Auto-generated method stub System.out.println(" 绘制三角形 "); } } //新增一个图形 class OtherGraphic extends Shape { OtherGraphic() { super.m_type = 4; } @Override public void draw() { // TODO Auto-generated method stub System.out.println(" 绘制其它图形 "); } }
1.6迪米特法则
-
基本介绍:
-
理论文字介绍太抽象,简单来说就是:A类—>B类的依赖—>A对B知道的越少越好,他们之间的交集越小越好。
-
还有一个简单的定义:只与直接的朋友通信
-
什么是直接的朋友?——有3种情况:
假定有一个A类、一个B类,
1-B类出现在A类的成员变量中
2-B类出现在A类的方法参数中
3-B类出现在A类的方法返回值中
-
-
1.7 合成复用原则
-
核心思想:则是尽量使用合成聚合的方式,而不是使用继承
-
简单理解:一个A类、一个B类,B类想用A类中的方法,如果直接继承的话耦合度太高。
解决的办法:
1-在B类的方法参数中传入A类(这是UML类图中的依赖);
2-在B类中写入A类的属性-就是A的对象实例,用set方法setA(A a)(这称为把A聚合到B里边去);
3-在B类中加入A的属性并直接new出A的对象(构建属性A时直接new出来),就是等于当B实例创建好了之后,我的属性A也创建好了(这样A和B事组合的关系)
图例:
这样做耦合度高的解释:(B类如果只想用A类中的2个方法,但A有5个方法,就会浪费;亦或者A类有其他的类被继承,A类的方法改变,B类也会受影响。)
-
设计原则的核心思想
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代
码混在一起 。 - 针对接口编程,而不是针对实现编程 。
- 为了交互对象之间的松耦合设计而努力
最后
以上就是个性小虾米最近收集整理的关于java设计模式的七大原则~(便于理解)的全部内容,更多相关java设计模式内容请搜索靠谱客的其他文章。
发表评论 取消回复