设计模式学习笔记
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
开闭原则
对拓展开放,对修改关闭,程序实现多运用接口和抽象类
里氏代换原则
当子类需要重写父类的方法时,需要定义一个接口定义重写的方法,父类与子类都实现接口,避免子类重写父类方法导致错误
依赖倒转原则
在模块之间进行交互时,高层模块应依赖低层模块的接口与抽象
例如Controller层的实各个类中使用的是Service层的service接口,而不是直接依赖service层中的Impl实现类
接口隔离原则
迪米特法则
在两对象之间插入中介的方式减少耦合
合成复用原则
减少实现过程中采用的继承,尽量使用组合和聚合
创建型模式(怎样创建对象)
单例模式
创建类对象方式
静态代码块
调用方法时创建对象
双重检查锁
静态内部类(推荐)
枚举(推荐)
破坏单例模式
序列化+反射
序列化方式
反射方式
破坏单例模式的解决方案
序列化解决
反射解决
单例设计模式应用——RunTime类
工厂模式
简单工厂模式
静态工厂模式
工厂方法模式
通过定义工厂类的接口,对factory对象的通用方法进行定义
抽象工厂模式
一个抽象工厂会定义多个不同的生产产品的方法
即AmericanDessertFactory工厂中存在产品AmericanCoffee和MatchaMousse,而IntalyDessertFactory工厂中存在产品Tiramisu和LatteCoffee
应用场景
工厂模式拓展(简单工厂+配置文件)
建造者模式
抽象builder类定义产品组装方法
指挥者类控制组装过程
拓展——内部builder
原型模式
创建型模式对比
结构型模式(怎样创建结构)
代理模式
通过构建代理类,在不改变火车站基本买票功能的基础上,实现了代售点卖票这一功能的增强
静态代理
通过代售点代理将一个火车站买票主题与客户端分离,使客户端不能直接访问火车站买票主题,即用户不需要去火车站即可购买到票
JDK动态代理
通过JDK的Proxy类构建代理类,注意此方法用到了匿名内部类IvocationHandler,对sellTickets接口的方法进行了映射
CGLIB代理
JDK方式使用接口代理,当没有实现接口时,使用CHLIB代理方式,不同于JDK形式基于反射实现,CGLIB基于继承实现
代理模式对比
适配器模式
将原来的接口转化为需要的另一个接口
类适配器模式
此适配器定义了一个类继承了要进行适配的类TFCardImpl,所以此类能够使用TFCardImpl中的方法,读取TF卡中的数据。
此类实现了目标接口SDCard,所以此类可以直接使用SDCard接口来与Computer类进行交互
实现了读取TFCard中的数据,用于只能读取SDCard计算机
对象适配器
TFCard接口作为成员变量,使用构造方法传入,不再继承TF接口
装饰者模式
与静态代理区别
桥接模式
将接口作为抽象类的成员变量,使用构造方法引入接口,从而实现抽象类与接口分离,便于分别实现拓展
外观模式
通过创建外观类,聚合各个功能的成员变量,使用构造方法引入,调用各个功能的方法
注意与代理模式进行区分:代理模式是通过继承的方式,来对功能进行增强,外观模式是通过使用成员变量调用方法,对外界提供统一的功能使用类
组合模式
构建目录等级系统,类似于二叉树
菜单实现类中另外聚合了抽象的根节点,此时它就可以用于实现多层菜单
分类
透明组合模式:方法全都定义在抽象根节点中
安全组合模式:抽线根节点中不会定义任何方法,而是在菜单类中定义
享元模式
BoxFactory使用单例设计模式创建,初始化时存储图形信息,每次需要访问图形时,只需要调用BoxFactory调用对应方法
行为型模式(怎样实现功能)
模板方法模式
策略模式(替代多重if-else)
多重if-else与策略模式对比
策略模式是一种行为型设计模式,它可以用来消除大量的if-else语句,提高代码的可维护性和可扩展性。策略模式将不同的算法封装到不同的类中,使得它们可以相互替换,而不影响客户端代码的使用。
以下是策略模式如何替代if的示例:
假设我们有一个计算器程序,可以对两个数字进行加、减、乘、除运算。使用if-else语句实现如下:
public class Calculator {
public int calculate(int a, int b, String operator) {
if (operator.equals("+")) {
return a + b;
} else if (operator.equals("-")) {
return a - b;
} else if (operator.equals("*")) {
return a * b;
} else if (operator.equals("/")) {
return a / b;
} else {
throw new IllegalArgumentException("Invalid operator: " + operator);
}
}
}
使用策略模式重构后的代码如下:
首先定义一个接口:
public interface Operation {
int apply(int a, int b);
}
然后实现不同的算法类:
public class AddOperation implements Operation {
@Override
public int apply(int a, int b) {
return a + b;
}
}
public class SubOperation implements Operation {
@Override
public int apply(int a, int b) {
return a - b;
}
}
public class MulOperation implements Operation {
@Override
public int apply(int a, int b) {
return a * b;
}
}
public class DivOperation implements Operation {
@Override
public int apply(int a, int b) {
return a / b;
}
}
最后在Calculator类中使用策略模式:
public class Calculator {
private Map<String, Operation> operations = new HashMap<>();
public Calculator() {
operations.put("+", new AddOperation());
operations.put("-", new SubOperation());
operations.put("*", new MulOperation());
operations.put("/", new DivOperation());
}
public int calculate(int a, int b, String operator) {
Operation operation = operations.get(operator);
if (operation == null) {
throw new IllegalArgumentException("Invalid operator: " + operator);
}
return operation.apply(a, b);
}
}
使用策略模式后,我们可以轻松地添加新的算法类,而不需要修改原有的代码。这样可以使代码更加灵活和易于维护
责任链模式
状态模式
观察者模式
观察者模式的核心思想是将被观察者和观察者解耦,使它们之间的依赖关系变得松散。被观察者只需要维护一个观察者列表,并在状态变化时通知观察者,而不需要关心具体的观察者是谁以及如何处理通知。观察者只需要注册到被观察者的观察者列表中,并实现自己的业务逻辑,不需要关心被观察者的具体实现。
JDK提供的观察者实现
中介者模式
迭代器模式
容器实现类
访问者模式
当数据结构中使用到元素,可以在元素改变时不会对数据结构产生影响
当需要添加用到元素的功能的时候,可以使用访问者进行拓展
备忘录模式
提供状态恢复机制,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
白箱备忘录
其中GameRole为发起人,类中提供saveStateMeMento和rollback方法用于保存当前状态和进行状态回滚
RoleStateMemento中定义了与GameRole相同的成员变量,用于记录成员状态,RoleStateCareTaker为管理者,实现GameRole状态的回滚
黑箱备忘录
不再创建RoleStateMemento类,而是在GameRole中创建RoleStateMemento内部类,对外提供Memento接口供RoleCareTacker使用
中…(img-eD1kqXTP-1718435493202)]
备忘录模式
提供状态恢复机制,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
白箱备忘录
其中GameRole为发起人,类中提供saveStateMeMento和rollback方法用于保存当前状态和进行状态回滚
RoleStateMemento中定义了与GameRole相同的成员变量,用于记录成员状态,RoleStateCareTaker为管理者,实现GameRole状态的回滚
[外链图片转存中…(img-cwKSTVMd-1718435493203)]
黑箱备忘录
不再创建RoleStateMemento类,而是在GameRole中创建RoleStateMemento内部类,对外提供Memento接口供RoleCareTacker使用
[外链图片转存中…(img-1O1jygfd-1718435493203)]