设计模式学习
设计模式大致分为三类。
- 创建者模式:提供一种创建对象的方式,同时隐藏了创建对象的逻辑。而不是直接使用new创建对象。
- 结构型模式:结构型模式更加关注对象与对象之间的关系与组合,旨在构建灵活可复用的类和对象结构。
- 行为型模式:关注类或对象之间的通信、协作、职责分配。旨在对象间的责任分配和算法封装。
记住所有的设计模式是愚蠢的,关注自己所在领域常用设计模式,语言框架中默认使用的设计模式。
创建型模式
创建者模式封装了创建对象的逻辑,将复杂对象的构建过程与其表示(使用)分离。代替手动用new操作符调用构造函数繁琐的过程。
优点:对象构造与表示分离,隐藏对象的内部结构。
工厂模式
工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。
分类:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
缺点:
增加了系统中的类和对象的个数,复杂度增加。
需要额外工作量创建和维护工厂类和产品类,增加开发成本。
应用场景:
- 日志配置器:日志记录层次、记录格式、记录的存放路径
1 | public class ShapeFactory { |
自己的应用:
深度学习中,经常需要对比不同学习模型的在相同任务上的效果。而不同的模型的创建逻辑大体相同,但部分细节不同。我自己写了一个模型工厂,根据传入的模型名称、模型层数、模块机制来自动构建模型。这样,每当我要改变一个模型训练,我就修改相应参数。
其实,这么说,整个深度学习任务的过程都可以看成工厂模式,只不过我没有做整个大任务的抽象封装。在Python代码中,我调用了一个argparse这么一个模块,它的作用就是解析命令行的参数。我训练一个任务,大体有数据集、模型、学习率、迭代次数这些个参数,每一次任务可以用参数组合表示。那么就是说我用参数组合来定义任务,这与工厂模式的思想是不谋而合的,我把要改变的地方全部提取出来,放到一起。
单例模式
单例模式也就说保证一个类只有一个实例存在,整个系统中只有一个全局对象。
应用场景:当系统只需要一个实例来协调整个系统的行为时
- 日志记录器
- 配置管理器
- windos中的任务管理器
单线程下实现方式:
- 私有化构造函数,使得构造函数无法通过外部调用;
- 创建一个持有字段hold,类型为对象的引用;
- 创建一个静态方法get,用于获得对象实例的引用。首先检查hold是否为空,为空才创建对象,否则返回引用。
多线程下实现注意点:
- 线程安全性,get方法得加锁
- 双重检查:在单例模式中,通常需要进行双重检查锁定,即先检查单例对象是否已经被创建,然后再加锁并再次检查。
- 饿汉式和懒汉式的选择:饿汉式在类加载时就完成了初始化,而懒汉式则在第一次调用getInstance方法时才进行初始化。
懒汉模式
1 | public class Singleton { |
饿汉模式
1 | public class Singleton { |
建造者模式
建造者模式将一个复杂对象分解成多个简单部分,对复杂对象分模块构建,一步步构建最终对象。
一般适合创建实例有多个步骤的复杂对象,比如说汽车有各个零件,每种零件的厂商是不固定的,但汽车的组装步骤是一定的。再提炼来说:一个复杂对象由各个部分的子对象组成,子对象可能会经常变化,而各个子对象的组合逻辑却不怎么变化。
1 | public class Computer { |
结构型模式
类与类之间的关系与组合,关注的是类间的布局。
装饰器模式
装饰器模式允许向一个对象添加新的功能,同时却不改变其原有代码。
应用:
- Java中的注解
- python里装饰器
- Spring框架的注解AOP
Java中可以自定义注解,然后通过反射的方式获取注解(注解拦截),然后进行功能增强。
适配器模式
适配器模式允许你将不兼容的对象包装成一个适配器类,使它们能够与其他对象一起工作。适配器模式通常用于处理与现有类库或框架不兼容的类或接口。
在STL里,栈和队列都是适配器,它们底层使用Deque作为容器存储,对外却表现为栈或队列的特性。
代理模式
unix系统调用中,错误包装函数。
我们需要从概念上了解代理和装饰的区别:
- 代理是全权代理,目标根本不对外,全部由代理类来完成。
- 装饰是增强,是辅助,目标仍然可以自行对外提供服务,装饰器只起增强作用。
行为型模式
行为型模式关注的是对象间的通信、写作、职责分配等。
责任链模式
将处理对象连成一条链,请求沿着链传递,直到有一个对象处理为止。
状态模式
对象的行为跟随着状态而改变。【状态机】
迭代器模式
提供一个方法顺序访问对象的各个元素,但不暴露对象的内部表示。
CPP的STL库里的迭代器就很好体现这一点。原生指针不足以支持元素的顺序访问,譬如链表节点、树的节点。迭代器的出现使得容器和算法分离,算法通过迭代器访问容器元素却不用知晓其实现,换句话说,算法更加通用。