java设计模式的七大原则~(便于理解)

1.设计模式的七大原则

  1. 单一职责原则
  2. 接口隔离原则
  3. 依赖倒转原则
  4. 里氏替换原则
  5. 开闭原则-ocp (工厂模式用到了这个)
  6. 迪米特法则
  7. 合成复用原则

1.1单一职责原则

  1. 概念:对类来说:一个类应该只负责一个职责

    如果A负责两个职责,A1.A2,为了避免职责A1发生变更后,影响职责A2的执行,需要把A进行粒度分解,分为A1,A2

  2. 优势及注意事项:

    1.降低类的复杂度

    2.提高程序的可读性、可维护性

    3.降低变更引起的风险

    4.遵守设计的单一原则

  3. 上代码

    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接口隔离原则

  1. 概念

    在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

理解:接口隔离—一个类依赖另一个类通常是通过一个接口来完成。

  1. 上代码

    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依赖倒转原则

  1. 基本介绍

    重点:

    它的中心思想是:面向接口编程

    抽象不依赖细节,细节依赖抽象

    接口和抽象类的目的是:指定规范

在这里插入图片描述

  1. 注意事项

    • 底层模块尽量都要有抽象类或接口。

    • 变量的声明尽量是一个接口,

      举例:加入一个类A继承了接口B,写一个Object obj = new A(); 其实这样的话,obj是直接与接口B有交接,等于是通过B来联系类A,这样中间就会有一个缓冲,接口B就是这个缓冲,

  2. 依赖传递的方式:

    • 接口传递
    • 构造方法传递
    • 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里氏替换原则

  1. 基本介绍:

    • 它是一个麻省理工的一个姓里的女士提出来的。
    • 它要求我们尽量的不要改写我们的父类的方法。(不要重写父类方法)
    • 如果重写了,可以通过聚合、组合、依赖来解决问题。
  2. 目的:

    就是保证父类的方法不被覆盖

  3. 上代码

    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. 基本介绍:

    • 开闭原则是编程中最基础最重要的原则

    • 对扩展开放,对修改关闭:——可以是用抽象创建框架,用实现来扩展细节。

      咂一看这句话有矛盾,我们来理解一下这句话:

      扩展开放——对提供者开放(可以理解为开发人员);

      修改关闭——对使用者关闭(可以理解为原先使用方的这边并没有修改)

    • 添加修改功能的时候尽量是扩展,不要进行修改。

  2. 方式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迪米特法则

  1. 基本介绍:

    • 理论文字介绍太抽象,简单来说就是:A类—>B类的依赖—>A对B知道的越少越好,他们之间的交集越小越好。

    • 还有一个简单的定义:只与直接的朋友通信

      • 什么是直接的朋友?——有3种情况:

        假定有一个A类、一个B类,

        1-B类出现在A类的成员变量中

        2-B类出现在A类的方法参数中

        3-B类出现在A类的方法返回值中

1.7 合成复用原则

  1. 核心思想:则是尽量使用合成聚合的方式,而不是使用继承

    1. 简单理解:一个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类也会受影响。)

设计原则的核心思想

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代
    码混在一起 。
  2. 针对接口编程,而不是针对实现编程 。
  3. 为了交互对象之间的松耦合设计而努力
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值