设计模式学习笔记
上大学时本专业未开设《设计模式》课程,加上自己对CS专业偏硬件的刻板印象,一直对设计模式不太上心,编程过程中随心所欲、毫无章法。到求职时愈发认识到设计模式的重要性,这一点从各大公司的招聘要求中可见一斑。过完年,便有心开始设计模式的学习。了解到设计模式种类繁多,需要深入理解才能掌握,故开此篇笔记记录琐碎知识和所想所悟。
参考书籍为《图解设计模式》
一 基础知识扫盲
本节记录书中涉及但本人遗忘的基础知识
1 Java基础
- 抽象类
没有方法主体的方法称为抽象方法,包含抽象方法的类就是抽象类。
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法。
- static关键字
①静态变量:某些特定的数据在内存中只有一份,而且能被一个类的所有实例对象共享,只用于修饰成员变量,不能用于修饰局部变量
②静态方法:在不创建对象的情况下直接调用类的某个方法
class Person{
public static void hello(){
System.out.println("Hello");
}
}
public class Demo{
public static void main(String[] args){
Person.hello();//直接用类名调用
Person person=new Person();//也可以通过实例化对象调用
person.hello();
}
}
③静态代码块:类被加载时,静态代码块会执行一次,在静态代码块中只能访问static修饰的成员。一个类只加载一次,所以静态代码块只执行一次
-
接口
接口里面的普通方法统一为抽象方法,可以有静态成员方法,但是必须有定义。成员变量统一被编译器规定为public static finla类型,即为常量,必须在定义时给定初值。
区别:抽象类只能实现单继承,接口可以实现多继承 -
super()
编译器会自动在子类构造函数的第一句加上 super()来调用父类的无参构造器
可通过super调用父类被子类重写的方法
二 设计模式
1 Iterator模式
不要只使用具体类来编程,要优先使用抽象类和接口来编程
(1)next方法是“返回当前元素,并指向下一个元素”
(2)hasNext方法是“确认接下来是否可以调用next方法”
(3)将遍历功能置于Aggregate角色之外是Iterator模式的一个特征
2 Adapter模式
用于填补“现有的程序”和“所需的程序”之间差异的设计模式
分为类适配器模式(继承)和对象适配器模式(委托)
(1)继承
上图中Banner为实际情况(220V交流电),Print为需求(12V直流电),PrintBanner为变换装置(电源适配器)
showWithParen()和showWithAster()均为Banner类的成员方法,printWeak()和printStrong()为Print接口中的抽象方法
(2)委托
在Java语言中,委托就是指将某个方法中的实际处理交给其他实例的方法
如上图,将printWeak的处理交由Banner的对象
很多时候我们经常会用到现成的类,特别是当现有的类已经过充分测试并已被广泛应用,我们更愿意将这些类作为组件重复利用
(3)个人总结
Adapter模式旨在使用现成的代码来实现预期功能。类适配器模式中目标为接口,可通过继承现有类来实现目标接口;对象适配器模式中目标为类,通过继承目标类,在新类中使用现有类的对象完成方法的委托
3 Template Method 模式
在父类中定义处理流程的框架,在子类中实现具体处理
如上图所示,父类的display方法定义了调用抽象方法的顺序,而具体抽象方法的实现便交由子类解决。这里的display方法即为模板方法。
关于A a = new B() ;这里的a并不是A的实例,而是B的实例。如果A有两方法: a1 a2 , B重载了其中一个 a2 , 那么 a.a1() 执行 A.a1, a.a2() 执行 B.a2()
里氏替换原则:无论在父类类型的变量中保存哪个子类的实例,程序都可以正常工作
个人总结:该模式定义了某个方法的固定处理流程,该方法一般在父类中定义为普通成员方法方便子类继承。该方法通过调用抽象方法形成模板方法(Template Method),通过各个子类对父类中同一抽象方法的不同实现方式实现模板的运用
4 Factory Method 模式
用Template Method模式来构建生成实例的工厂,就是Factory Method模式(类创建模式)
在该模式中,父类决定子类的生成方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责
只要是Factory Method模式,在生成实例时就一定会使用到Template Method模式
上图为产品类,定义了“产品是可以被use的东西”
在上图中,定义了工厂是用来“调用create方式生成Product实例”的
个人总结:总工厂定义产品的生产规范,生产新的产品便需要引入新的生产线,即子类工厂,将创建对象的工作交给工厂的子类
5 Singleton模式
确保只生成一个实例的模式
任何情况下都绝对只有一个实例
如上图所示,定义static字段并初始化为该类的实例,初始化行为仅在该类被加载时进行一次。构造函数为private,禁止从本类的外部调用构造函数,若在外部使用new Singleton(),就会出现编译错误
6 Prototype模式
在不指定类名的前提下生成实例
在涉及模式中,指依据实例原型、实力模型来生成新的实例
核心为Java语言的clone方法、被复制对象的类必须实现java.lang.Clonable接口
以飞机为例,复制一架飞机需要其内部的所有零部件信息,工作量巨大。该模式将对飞机的复制委托给飞机本身,即飞机类内部需要实现原型接口并重写其中的clone方法,以返回以自身属性为基础的新对象。
一般在初始化的信息不发生变化的情况下,克隆是最好的办法。动态地获得对象运行时的状态,隐藏了对象创建的细节,大大提高了性能。
7 Builder模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
用户只需指定要建造的类型即可得到它们,不必得知具体建造的过程和细节
Director类是建造者模式中的一个重要类,用于控制建造过程、隔离用户与建造过程的关联
与Template Method模式区别:Builder模式中引入第三方类,与父类子类均无关,方法的组装从父类转移到了第三方类Director
适用场景:主要用于创建一些复杂的对象,这些对象内部构建的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化
8 Abstract Factory模式
该模式旨在创建一组对象。与工厂方法模式相比, 抽象工厂模式中的具体工厂不只是创建一种具体对象,它负责创建一组(族)具体对象
9 Bridge模式
(1)类的功能层次结构(希望增加新功能)
- 父类具有基本功能
- 在子类中增加新的功能
(2)类的实现层次结构(希望增加新的实现) - 父类通过声明抽象方法来定义接口
- 子类通过实现具体方法来实现接口
Bridge模式的作用是在“类的功能层次结构”和“类的实现层次结构”之间搭建桥梁
如上图,将抽象部分与它的实现部分分离,使它们都可以独立地变化
10 Strategy模式
使用Strategy模式可以整体地替换算法的实现部分,能够整体地替换算法,以不同的算法解决同一个问题
使用委托这种弱关联关系可以很方便地整体替换算法
11 Composite模式(组合模式)
需求中体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式
例:树的叶节点和分支结点,文件与文件夹
如上图所示,叶节点和枝节点实现同一个接口,对于外界没有区别,具备完全一致的行为接口
12 Decorator模式(装饰模式)
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活
装饰模式是为已有功能动态地添加更多功能的一种方式
例:数据加密和关键字过滤
缺点:会导致程序中增加许多功能类似的很小的类
13 Visitor模式
访问者模式讲的是表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
访问者模式适用于数据结构相对稳定的系统(如性别只有男女),把数据结构和操作分离,使得操作集合可以相对自由地演化
14 Chain of Responsibility模式(职责链)
将多个对象组成一条职责链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责处理
15 Facade模式(外观)
为互相关联在一起的错综复杂的类整理出高层接口,Facade角色可以让系统对外只有一个简单的接口
类比股票和基金
16 Mediator模式(中介者)
迪米特法则:如何两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用
如上图所示,联合国即为Mediator(中介者)
17 Observer模式(观察者)
在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。适用于根据对象状态进行相应处理的场景
18 Memento模式(备忘录)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
适用于功能较复杂的,需要维护或记录属性历史的类
19 State模式(状态)
用类表示具体的状态(如把if判断白天和夜晚改为白天类和夜晚类)
20 Proxy模式(代理)
不一定需要本人亲自进行工作时,寻找代理人完成工作,当代理遇到无法自己解决的事时,回去找本人解决
实例:HTTP代理
21 Command模式(命令)
将请求封装为一个对象,可用不同的请求对客户进行参数化;对请求排队或记录请求日志,支持可撤销的操作
23 Interpreter模式(解释器)
给定一个语言,定义它的文法的一种表示,并定义一个解释器,用来解释语言中的句子
如遥控汽车的遥控程序,将前进、后退、左右转弯翻译为具体的控制信号
24 FlyWeight模式(享元)
运用共享技术有效地支持大量细粒度地对象
如果程序中使用了大量的对象,且这些对象造成了很大的存储开销时,应考虑使用享元模式