OO 原则是我们的目标,而设计模式是我们的做法。
最近写 java 半年多,虽然这门语言看上去有一丝笨重和啰嗦,但和设计模式遇上,就好像咖啡与牛奶的融合,变成一杯香醇的拿铁🤔。本文做为个人的读书笔记(水一篇博客),同时如果能帮到你就更好啦!
分类
大家应该还知道一本书,叫做 《设计模式:可复用面向对象软件的基础》,其中非常精辟的将设计模式分为三类(持续学习更新中):
- 创建型 - Creational
- (类)工厂方法模式(Factory Method) -> 第四章:工厂模式
- 抽象工厂模式(Abstract Factory)
- 创建者模式(Builder)
- 原型模式(Prototype)
- 单例模式(Singleton) -> 第五章:单例
- 结构型模式 - Structural
- (类)适配器模式(Adapter) -> 第七章:适配器模式
- 外观模式/门面模式(Facade门面模式)
- 代理模式(Proxy) -> 第十一章:代理模式
- 装饰模式(Decorator) -> 第三章:装饰者模式
- 桥梁模式/桥接模式(Bridge)
- 组合模式(Composite)
- 享元模式(Flyweight)
- 行为模式 - Behavioral
- (类)模板方法模式(Template Method) -> 第八章:模版方法模式
- (类)解释器模式(Interpreter)
- 职责链模式(Chain of Responsibility)
- 观察者模式(Observer) -> 第二章:观察者模式
- 状态模式(State) -> 第十章:状态模式
- 策略模式(Strategy)
- 命令模式(Command) -> 第六章:命令模式
- 访问者模式(Visitor)
- 调停者模式(Mediator)
- 备忘录模式(Memento)
- 迭代器模式(Iterator) -> 第九章:迭代与组合模式
章节
第一章:策略模式 - 整合鸭子的行为
将易变的属性,做为一个对象变量去初始化进行组合(行为也是一种对象!)
第二章:观察者模式 - The Observer Pattern
稍微解释一下:不同的 Display 在实例化时,会在 WeatherData 中被注册为「观察者」统一管理,当「被观察者」(气象数据)发生变化时统一触发通知。
目的:让观察者和被观察者,尽可能的解耦。
效果:
1 | WeatherData weatherData = new WeatherData(); |
第三章:装饰者模式 - The Decorator Pattern
当遇到继承无法解决的问题,可以尝试使用更为优雅的装饰者模式:
最终效果如下,但初始化的方式有点简陋。文中也提到后续 “工厂” & “生成器” 模式,将有更好的方式建立被装饰对象。
1 | // 来一杯 Espresso |
第四章:工厂模式 - The Factory Pattern
简单工厂其实不是一个设计模式,反而更像是一种编程习惯。
在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。例如下面代码中
1 | SimplePizzaFactory factory = new SimplePizzaFactory(); |
章节中还提到了抽象工厂模式,本质上是两层的 factory,感觉有点太花了。。感兴趣可以阅读原文。
第五章:单例 - Singleton
再熟悉不过的老朋友,就不多说了。简单回答两个问题:
Q: 为什么不直接使用全局变量呢?
A: 因为需要在一开始就创建好对象,但实际一直没有用到,造成资源的浪费。有种类似 lazyload 的意思。
Q. 什么需要单例呢?
A: 确保一个类只有一个实例,并提供一个全局访问点。
效果:
1 | // 注意有个小细节:Singleton 的构造器是私有的,意味着无法被直接 new 出来(实例只能通过工厂模式创造出来) |
第六章:命令模式 - The Command Pattern:
RemoteLoader 可能有点困惑,其他可以简单将它理解为 main
函数,将 Light 和 LightOnCommand 绑定,并将 command 与 remoteControl 绑定:
效果:
1 | remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); |
命令模式的思考在于,允许将动作封装为命令对象,这样一来可以随心所欲的存储、传递和调用它们。
第七章:适配器模式 - adapter
Target 理解为鸭子,拥有 fly 与 quack 的接口。
Adaptee 是火鸡,只有 fly 和 gobble 接口。
Adaptor 继承了 Target 接口,并根据火鸡的特效实现了对应的鸭子接口。
最终达到与 client 交互时,可以直接把它当作一只鸭子。
三个的区别:
- decorator: 将一个接口转成另外一个接口
- adaptor: 不改变接口,但加入责任
- facade: 让接口更简单(对一个复杂子系统包装,只暴露一个干净的外观)
最终目的:当设计一个系统时,尽可能的降低客户与系统之间的耦合
效果:
1 | Duck duck = new MallardDuck(); |
第八章:模版方法模式 - The Template Method Pattern
想起了公司业务代码中的 ServiceTemplate,一个道理。
⚠️注意抽象类中 brew 和 addCondiments 方法 是用斜体标示的,需要让子类实现对应细节。而抽象类统一管理统一的处理流程与子步骤,并暴露给客户代码(减少整个系统的依赖)。
第九章:迭代与组合模式 - The Iterator and Composite Patterns
迭代器模式,针对底层不同的 数组、列表、散列表等,统一为迭代器的对外接口。
第十章:状态模式 - The State Pattern
状态机。最近在做一个 telegram 群组管理的机器人,对于用户状态的管理,刚好也可以用到这个设计模式:
效果:
1 | GumballMachine gumballMachine = new GumballMachine(5); |
第十一章:代理模式 - The Proxy Pattern
没太懂,找了几个 proxy 模式的应用场景:
- 银行账号:通过该账号管理我们的资金。目标为 controls and manage access to the object they are "protecting".
- db 连接的 client,相关配置需要提前被初始化好。
- 但命令一个程序员去写代码的时候,在完成需求 crud 的同时,还要补充文档!
静态 proxy:
动态 proxy:
- TODO
第十二章:模式的模式 - Compound Pattern
相当于将上面讲解过的设计模式复合使用,刚好跟着敲一遍代码,复习一下。
但像文中说的那样,有种牛刀杀鸡的感觉。。