面向对象设计模式分类与6大设计原则

单一职责...

Posted by MetaNetworks on December 22, 2020
本页面总访问量

设计模式的分类

参考:菜鸟教程:设计模式

  • 创建型
    • 单例模式
    • 工厂方法模式
      • 需要时new一个
    • 抽象工厂模式
    • 建造者模式
      • 对外隐藏类的构造方法,通过Builder类提供的方法进行构造
    • 原型模式
  • 结构型
    • 代理模式
    • 装饰模式
    • 适配器
      • 用于兼容两个不兼容的接口
    • 组合模式
    • 桥梁模式
    • 外观模式
    • 享元模式
  • 行为型
    • 模板方法模式
    • 命令模式
    • 责任链模式
    • 策略模式
    • 迭代器模式
    • 中介者模式
    • 观察者模式
    • 备忘录模式
    • 访问者模式
    • 状态模式
    • 解释器模式

面向对象6大设计原则

单一职责原则(SRP Single Responsibility Principle)

理念:如果一个类包含了多个职责功能, 那么不管哪个功能需要修改, 都会导致这个类需要修改

例如:Android下的MVP模式,若presenter得到数据带有逻辑参数(如数据是否是缓存),不应该传递给view层。要是之后数据缓存逻辑变化,还要改单一负责数据展示的view层。

开闭原则(OCP Open-Closed Principle)

理念:一个软件实体应当对扩展开放, 对修改关闭,在不修改原有代码的情况下改变他的行为

例如:Android下MVP中,如果Presenter下的Model需要改变数据来源,可以直接新建一个实现IData接口的类,替换掉Presenter中原有定义的IData类。

例子:Java接口中的常量均为public static final类型的,如果不是final的话,则任意实现该接口的类都能对其进行任意修改,不符合OCP原则。

里氏替换原则(Liskov Substitution Principle)

理念:所有引用基类的地方必须能够使用其子类对象, 而且替换成子类也不会产生任何错误或异常

例如:Java会校验该原则,以下是报错例子:如果重载一个方法,从public重载到private域,在编译阶段就会失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 声明一个父类
public class Parent {
    public void test(){
    }
}

// 继承父类
public class Liskov extends Parent {
    // 覆写父类的方法, 将访问控制符改成 private
    @Override
    private void test() {
        super.test();
    }
}

接口隔离原则(Interface Segregation Principle)

理念:客户端不应该依赖它不需要的接口 或者 类间的依赖关系应该建立在最小的接口上

例如:以下代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Mechanic {
    void repairCar(ICar car);
}

interface ICar {
    void repair();
    void sell();
}

class Car implements ICar {
    void repair() {
        //...
    }
    void sell() {
        //...
    }
}

修理工拿到ICar的接口类,可以调用sell出售的方法,但是修理工不负责修理,也就是说同一个接口中出现了不同的职能功能。此处不合理,即可以进行拆分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface IRepairable {
    void repair();
}

interface ISellable {
    void sell();
}

class Mechanic {
    void repairCar(IRepairable repairable);
}

interface ICar extends IRepairable, ISellable {
}

class Car implements ICar {
    void repair() {
        //...
    }
    void sell() {
        //...
    }
}

一直拆成更细的接口可以解决耦合问题。但是不一定带来收益

拆的很细,要是后来需求变动,需要接口增加为原接口的某种组合,此时又要维护接口,太麻烦。一定要满足单一职责原则,违反的话没必要进行

粒度太小,接口数量剧增,粒度太大,不利于代码重用,灵活性降低。

依赖倒置原则

面向接口(或抽象类)编程

理念:

  • 高层模块不依赖低层模块
  • 两者都依赖其抽象
  • 细节应该依赖抽象
1
2
3
4
5
6
7
public class Client {
    public static void main(String[] args){
        IDriver zhangsan = new Driver();
        ICar bmw = new BMW();
        zhangsan.drive(bmw);
    }
}

迪米特法则(Law of Demeter / Least Knowledge Principe)

理念:只和需要耦合的对象交流,对朋友(依赖的对象)最少的了解

只和需要耦合的对象交流
  • 一个类中的方法可以访问本类中的其他方法
  • 一个类中的方法可以访问本类中的字段,但不能访问字段的字段
  • 在方法中可以直接访问其参数的方法
  • 在方法中创建的局部变量,可以访问局部变量的方法
  • 在方法中不应该访问全局对象的方法(能否作为参数传递进来)
对朋友最少的了解

例子:安装类有第一步、第二步、第三步。这些应该为private方法,并建立一个public类“安装”,封装安装过程,暴露给其他方法。