1.设计模式的目的

​ 设计模式是为了让程序(软件)具有以下特点:

  • 代码重用性
  • 可读性
  • 可扩展性
  • 可靠性(即增加新的功能后对原来的功能没有影响)
  • 使程序呈现高内聚,低耦合的特性

2.七大原则

2.1 单一职责原则

2.1.1 基本介绍

即一个类应该只负责一项职责。如类A负责两个不同职责(并不是只能有一个方法),当因为职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2

2.1.2 应用实例

方式1:

public class singleresponsibility1 {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("plane");
        vehicle.run("car");
    }
}
// 方式1:
// 分析:在run中违反了单一职责原则
// 方案:需要根据交通根工具运行方式不同分解为不同类
class Vehicle{
    public void run(String vehicle){
        if (vehicle == "car"){
            System.out.println(vehicle+" run on the road");
        }
        else if (vehicle == "plane"){
            System.out.println(vehicle+" run on the sky");
        }
    }
}

方式2:

public class singleresponsibility2 {
    public static void main(String[] args) {
        RoadVehicle roadVehicle = new RoadVehicle();
        roadVehicle.run("car");
        AirVehicle airVehicle = new AirVehicle();
        airVehicle.run("plane");
    }
}
// 方法2:
// 分析:遵守了单一职责原则,但是需要将类分解,同时修改客户端(即main中的代码)
// 方案:直接修改Vehicle类
class RoadVehicle{
    public void run(String vehicle){
        System.out.println(vehicle + " run on the road");
    }
}
class AirVehicle{
    public void run(String vehicle){
        System.out.println(vehicle + " fly on the sky");
    }
}

方式3:

public class singleresponsibility3 {
    public static void main(String[] args) {
        Vehicle2 vehicle2 = new Vehicle2();
        vehicle2.runAir("plane");
        vehicle2.runRoad("car");
    }
}
// 方法3:
// 分析:没有对原来的类进行大的修改。虽然没在类级别上遵循单一职责原则,但是在方法级别上遵循了
class Vehicle2{
    public void runAir(String vehicle){
        System.out.println(vehicle+" run on the sky");
    }
    public void runRoad(String vehicle){
        System.out.println(vehicle+" run on the road");
    }
}

2.1.3 注意事项和细节

  • 降低类的复杂度(即一个类只负责一项职责)
  • 提高类的可读性和可维护性
  • 降低变更引起的风险
  • 当类中方法数量足够少时可以在方法级别保持单一职责原则

2.2 接口隔离原则

2.2.1 基本介绍

客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上

2.2.2 应用实例

下面代码中,Interface1对于A和C而言不是最小接口,B和D必须实现它们不需要的方法

interface Interface1 {
    void operation1();

    void operation2();

    void operation3();

    void operation4();

    void operation5();
}

class B implements Interface1 {

    @Override
    public void operation1() {
        System.out.println("B实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("B实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("B实现了operation3");
    }

    @Override
    public void operation4() {
        System.out.println("B实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("B实现了operation5");
    }
}

class D implements Interface1 {

    @Override
    public void operation1() {
        System.out.println("D实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("D实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("D实现了operation3");
    }

    @Override
    public void operation4() {
        System.out.println("D实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("D实现了operation5");
    }
}

// A类通过接口Integface1依赖(使用)B类,但是只会用到operation1,operation2,operation3方法
class A {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend12(Interface1 i) {
        i.operation2();
    }

    public void depend3(Interface1 i) {
        i.operation3();
    }
}

// C类通过接口Integface1依赖(使用)D类,但是只会用到operation1,operation4,operation5方法
class C {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend14(Interface1 i) {
        i.operation4();
    }

    public void depend5(Interface1 i) {
        i.operation5();
    }
}

将Interface1拆分为Interface1,Interface2,Interface3

public static void main(String[] args) {
    A a = new A();
    // A类通过接口依赖B类
    a.depend1(new B());
    a.depend2(new B());
    a.depend3(new B());

    C c = new C();
    // C类通过接口依赖D类
    c.depend1(new D());
    c.depend4(new D());
    c.depend5(new D());
}
interface Interface1 {
    void operation1();
}

interface Interface2 {
    void operation2();

    void operation3();
}

interface Interface3 {
    void operation4();

    void operation5();
}

class B implements Interface1, Interface2 {

    @Override
    public void operation1() {
        System.out.println("B实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("B实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("B实现了operation3");
    }
}

class D implements Interface1, Interface3 {

    @Override
    public void operation1() {
        System.out.println("D实现了operation1");
    }


    @Override
    public void operation4() {
        System.out.println("D实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("D实现了operation5");
    }
}

// A类通过接口Integface1和Interface2依赖(使用)B类
class A {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend2(Interface2 i) {
        i.operation2();
    }

    public void depend3(Interface2 i) {
        i.operation3();
    }
}

// C类通过接口Integface1和Interface3依赖(使用)D类
class C {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend4(Interface3 i) {
        i.operation4();
    }

    public void depend5(Interface3 i) {
        i.operation5();
    }
}

2.3 依赖倒转原则

2.3.1 基本介绍

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象(抽象指抽象类或接口,细节就是具体的类)
  • 依赖倒转(倒置)的中心思想是面向接口编程

2.3.2 应用实例

方法1:

public static void main(String[] args) {
    Person person = new Person();
    person.receive(new Email());
}
class Email {
    public String getInfo() {
        return "email info:hello world!";
    }
}

// 完成Person接收消息的功能:
// 方式1:简单易实现,但是如果获取的对象是微信不是邮件,则需要新增微信类并且Person类也需要添加相应的方法
// 解决方案: 引入抽象接口IReceiver表示接收者,Person类与该接口发生依赖
//          此时邮件或微信只需要实现该接口即可
class Person {
    public void receive(Email email) {
        System.out.println(email.getInfo());
    }
}

方法2:

public static void main(String[] args) {
    // 客户端无需改变
    Person person = new Person();
    person.receive(new Email());
    person.receive(new WeChat());
}
// 定义接口IReceiver
interface IReceiver{
    public String getInfo();
}
class Email implements IReceiver{
    public String getInfo() {
        return "email info:hello world!";
    }
}
class WeChat implements IReceiver{
    public String getInfo() {
        return "WeChat info:hello world!";
    }
}
class Person {
    // 对类的依赖改为对接口的依赖
    public void receive(IReceiver receiver) {
        System.out.println(receiver.getInfo());
    }
}

2.3.3 注意事项和细节

  • 低层模块尽量都要有抽象类或接口,或者两者都有
  • 变量的声明类型尽量是抽象类或接口
  • 继承时遵循里氏替换原则
  • 依赖关系传递的三种方式(即把接口写在哪种方法的参数中):
    • 接口传递
    • 构造方法传递
    • setter方法传递

3.参考

https://www.bilibili.com/video/BV1G4411c7N4?p=5-13

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐