美文网首页
设计模式:七大原则及各种模式的分类

设计模式:七大原则及各种模式的分类

作者: Teemo_fca4 | 来源:发表于2020-05-07 21:07 被阅读0次
单一职责原则

介绍:简单理解为不要一段代码做所有功能,应该分类来做,比如

public class SingleResponsibility1 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Vehicle vehicle = new Vehicle();
        vehicle.run("摩托车");
        vehicle.run("汽车");
        vehicle.run("飞机");
    }
}
// 交通工具类
// 方式1
// 1. 在方式1 的run方法中,违反了单一职责原则
// 2. 解决的方案非常的简单,根据交通工具运行方法不同,分解成不同类即可
class Vehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上运行....");
    }
}
// 所有东西在在这个方法跑,违反了单一原则
class Vehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上运行....");
    }
}
//可以改进为以下
public class SingleResponsibility3 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Vehicle2 vehicle2  = new Vehicle2();
        vehicle2.run("汽车");
        vehicle2.runWater("轮船");
        vehicle2.runAir("飞机");
    }

}

//1. 这种修改方法没有对原来的类做大的修改,只是增加方法
//2. 这里虽然没有在类这个级别上遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责
class Vehicle2 {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上运行....");    
    }
    
    public void runAir(String vehicle) {
        System.out.println(vehicle + " 在天空上运行....");
    }
    
    public void runWater(String vehicle) {
        System.out.println(vehicle + " 在水中行....");
    }
    //..
}
接口隔离原则

介绍:简单理解调用方不应该依赖它不需要的接口方法,即一个类对另一个类的依赖应该建立在最小接口上

public class Segregation1 {

   public static void main(String[] args) {
   }
}

//接口
interface Interface1 {
   void operation1();
   void operation2();
   void operation3();
   void operation4();
   void operation5();
}

class B implements Interface1 {
   public void operation1() {
       System.out.println("B 实现了 operation1");
   }
   
   public void operation2() {
       System.out.println("B 实现了 operation2");
   }
   public void operation3() {
       System.out.println("B 实现了 operation3");
   }
   public void operation4() {
       System.out.println("B 实现了 operation4");
   }
   public void operation5() {
       System.out.println("B 实现了 operation5");
   }
}

class D implements Interface1 {
   public void operation1() {
       System.out.println("D 实现了 operation1");
   }
   
   public void operation2() {
       System.out.println("D 实现了 operation2");
   }
   public void operation3() {
       System.out.println("D 实现了 operation3");
   }
   public void operation4() {
       System.out.println("D 实现了 operation4");
   }
   public void operation5() {
       System.out.println("D 实现了 operation5");
   }
}

class A { //A 类通过接口Interface1 依赖(使用) B类,但是只会用到1,2,3方法 ,4 和5 方法白写了
   public void depend1(Interface1 i) {
       i.operation1();
   }
   public void depend2(Interface1 i) {
       i.operation2();
   }
   public void depend3(Interface1 i) {
       i.operation3();
   }
}
 
class C { //C 类通过接口Interface1 依赖(使用) D类,但是只会用到1,4,5方法  ,2 ,3 白写了
   public void depend1(Interface1 i) {
       i.operation1();
   }
   public void depend4(Interface1 i) {
       i.operation4();
   }
   public void depend5(Interface1 i) {
       i.operation5();
   }
}

//将接口方法重新组合来改进,将上面的接口方法分割成小接口,再来各自实现
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();
   }
}

感觉这种方法不够灵活呀,假设现在有一个方法,需要调用方法2和方法4,那我们改怎么办?

依赖倒转原则

介绍:依赖倒转主要思想是面向接口编程,接口或者抽象类来制定规范,高层只需要和接口对接,具体的实现让底层去实现,这样接口就相当于一个中间层来起桥梁和缓冲作用。

public class DependecyInversion {

    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
    }

}

class Email {
    public String getInfo() {
        return "电子邮件信息: hello,world";
    }
}

//Person 直接依赖Email,不符合依赖倒转原则
class Person {
    public void receive(Email email ) {
        System.out.println(email.getInfo());
    }
}

//使用接口来改进

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());
    }
}

依赖倒转一般有三种方式:接口传递,构造方法传递,setter方法传递

// 方式1: 通过接口传递实现依赖,调用方定义接口,提供方也定义一个接口
// 调用方的接口
 interface IOpenAndClose {
     public void open(ITV tv); //抽象方法,接收接口
 }
//提供方的接口
 interface ITV { //ITV接口
     public void play();
 }
 
 class ChangHong implements ITV {
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println("长虹电视机,打开");
    }
 }
// 实现接口
 class OpenAndClose implements IOpenAndClose{
     public void open(ITV tv){
         tv.play();
     }
 }
 //新增一个电视时只需要加一个电视即可,下面的构造器传递和setter传递也一样
 class Haier implements ITV {
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println("海尔电视机,打开");
    }
 }

    public static void main(String[] args) {
        ChangHong changHong = new ChangHong();
        OpenAndClose openAndClose = new OpenAndClose();
        openAndClose.open(changHong);
        openAndClose.open(new Haier());
    }

 //方式2: 通过构造方法依赖传递
 interface IOpenAndClose {
     public void open(); //抽象方法
 }
 interface ITV { //ITV接口
     public void play();
 }
 class OpenAndClose implements IOpenAndClose{
     public ITV tv; //成员
     public OpenAndClose(ITV tv){ //构造器
         this.tv = tv;
     }
     public void open(){
         this.tv.play();
     }
 }
 class ChangHong implements ITV {
        @Override
        public void play() {
            // TODO Auto-generated method stub
            System.out.println("长虹电视机,打开");
        }
}
    public static void main(String[] args) {
        ChangHong changHong = new ChangHong();
        //通过构造器进行依赖传递
        OpenAndClose openAndClose = new OpenAndClose(changHong);
        openAndClose.open();
    }

// 方式3 , 通过setter方法传递
interface IOpenAndClose {
    public void open(); // 抽象方法

    public void setTv(ITV tv);
}

interface ITV { // ITV接口
    public void play();
}

class OpenAndClose implements IOpenAndClose {
    private ITV tv;

    public void setTv(ITV tv) {
        this.tv = tv;
    }

    public void open() {
        this.tv.play();
    }
}
class ChangHong implements ITV {
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println("长虹电视机,打开");
    }
}
    public static void main(String[] args) {
        ChangHong changHong = new ChangHong();
        //通过setter方法进行依赖传递
        OpenAndClose openAndClose = new OpenAndClose();
        openAndClose.setTv(changHong);
        openAndClose.open();
    }
里氏替换原则

介绍:父类已经实现实现好的方法,其实是给子类的一个默认实现,子类不应该任意去重写这些方法,否则就会对整改继承体系造成破坏,可以通过聚合,组合,依赖,来解决问题

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();
        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类
class A {
    // 返回两个数的差
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends A {
    //这里,重写了A类的方法, 可能是无意识
    public int func1(int a, int b) {
        return a + b;
    }

    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
}

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);
    }
}
开闭原则

开闭原则是最基础也是最重要的原则,一个模块,类,函数等,应该对提供方实现扩展开放,对使用放实现修改关闭。当软件功能变化时,尽量通过扩展软件实体的行为而不是修改已有代码来实现。

//这是一个用于绘图的类 [使用方]
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;
    }
}
    public static void main(String[] args) {
        //使用看看存在的问题
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
    }

加上我们需要新增一个图形,那么我们需要修改使用方drawShape方法 多加一个if else,还要增加一个画图方法,这不符合开闭原则,因为修改了调用方的代码,下面改进方法,改进后的代码如果需要实现新功能,调用方代码无需修改,同时也满足了功能扩展的需求。

//这是一个用于绘图的类 [使用方]
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(" 绘制其它图形 ");
    }
}
    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());
    }
迪米特原则
合成复用原则
设计模式的分类

创建型:单例模式,工厂模式,原型模式,建造者模式
结构型模式:适配器模式,桥接模式,装饰器模式,组合模式,外观模式,享元模式,代理模式
行为型模式:模板方法模式,命令模式,访问者模式,迭代模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,责任链模式。

相关文章

网友评论

      本文标题:设计模式:七大原则及各种模式的分类

      本文链接:https://www.haomeiwen.com/subject/qivbpctx.html