Design Patterns:Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, thus making it easier to reuse successful designs and architectures.
经典的设计模式通常指由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人(他们被称为 “Gang of Four” 或 “GoF”)在著作《Design Patterns: Elements of Reusable Object-Oriented Software》中描述的 23 种设计模式。
创建型模式
如何创建对象
单例模式
Singleton pattern:保证一个类仅有一个实例,并提供一个访问它的接口
单例的构造方法必须是
private
,不能 new Xxx()
来创建实例了,防止创建出不止一个实例,但是在类的内部,是可以用一个静态字段来引用唯一创建的实例。应用场景
有频繁实例化然后销毁的情况,或创建对象耗时过多或者耗资源过多
➡️ 经常访问 I/O 资源的对象
- Operating system using file system to manage files
- Static configuration data (Configuration files)
- Object for logging (Logger)
- Access to cache storage
- Thread pools
- Interface to access hardware
(2022 Final Exam) Briefly discuss when a singleton design pattern should be used in an object-oriented software.
The singleton design pattern is used when you need to ensure that there is only one instance of a particular class in your application, for example,
- Resource management
- Configuration management
- Caching
- Logging
对比分析
ㅤ | Static Methods | Singleton |
Accessibility | Every class can freely access static variables | Easy to control who gets the instance |
Flexibility | Only one copy exactly | Can be configured with a specified number of instances if needed |
Clarity | Can pollute name spaces (e.g., in the context of C++) | No need to create globally visible variables |
- 大型程序往往会使用多个独立开发的库,这些库又会定义大量的全局名字(如类、函数等)。当应用程序用到多个供应商提供的库时,不可避免地会发生某些名字相互冲突的情况。多个库将名字放置在全局命名空间中将引发命名空间污染。
优点
- Have strict control over how and when a client can access an instance of a class.
- Can be used to replace globe variables.
- Control the number of instances that can be created.
缺点
- Need to be careful when used in a multi-threaded environment.
这种写法在多线程中是错误的,在竞争条件下会创建出多个实例。必须对整个方法进行加锁,但加锁会严重影响并发性能。
工厂方法
Factory Method pattern:定义一个用于创建对象的接口,通过接受参数,让子类决定实例化哪一个类。
- Decouples application-specific classes from the instantiation of concrete types.
- 创建对象和使用对象是分离的,使我们不用主动创建对象,而是让工厂来帮创建对象。
例子🍕
假设有一个披萨店,有多种口味的披萨,现在需要根据客户的需求来生产不同口味的披萨。
定义抽象披萨类,包含了披萨的一些基本属性和方法
定义多个具体的披萨类,继承自抽象披萨类,实现特定的制作流程
定义披萨店类,它包含一个披萨工厂方法
定义具体的披萨店类,实现具体的披萨制作流程
最后客户端代码可以完全忽略真正的披萨工厂 PizzaStore
应用场景
Consider using a factory pattern when
- a class can't anticipate the class of objects it must create
- a class wants its subclasses to specify the objects it creates
➡️ Use an interface for creating an object, but let subclasses decide which class to instantiate.
For example,
- Log Parser:用户选择记录日志到什么地方(本地硬盘、系统事件、远程服务器等)
- Dependency injection
- Plugin architecture: allow third-party plugins to extend the functionality of your application
结构型模式
如何组合对象以便获得更灵活的结构
外观模式
Facade Pattern: provide a simple interface to a complex subsystem
如果客户端要跟许多子系统打交道,那么客户端需要了解各个子系统的接口,比较麻烦。
如果有一个统一的“中介”,让客户端只跟中介接触,中介再去跟各个子系统接触,对客户端来说就比较简单。Facade 就相当于搞了一个中介。
例子 🌰
应用场景
When you want to provide a simplified interface to a complex system or set of classes:
- Operating systems use façade to compose many frameworks into one.
- Program compilers use façade to make programmers’ life easier.
- Web services use a façade to act as an entry point.
- 复杂的 Web 程序,会有多个 Web 服务,这个时候,经常会使用一个统一的网关入口 Gateway 来自动转发到不同的 Web 服务
- Database connectors, e.g., Java Database Connectivity (JDBC) use façade to hide the complexity of establishment of connections.
适配器模式
Adapter Pattern:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容 (incompatible) 而不能一起工作的那些类可以一起工作。
接口适配器 / 类适配器 / 对象适配器
由于 Java 中不支持多重继承(一个类可以从多个父类中继承它们的所有属性和方法),因此类适配器只能适配一个适配者类。如果要适配多个适配者类,则需要使用对象适配器。
ㅤ | Class Adapter | Object Adapter |
Compatibility | Adapts a class and all its subclasses | Adapts a single or multiple classes |
Overriding | Overrides some of Adaptee's behavior | Harder to override Adaptee's behavior |
Flexibility | Less flexible, as it's limited to a single Adaptee class | More flexible, as it can add functionality to all Adaptees |
Code structure | Uses inheritance to adapt the Adaptee | Uses object composition to adapt the Adaptee |
- 对象组合(Object Composition)是一种设计模式,它将多个对象组合在一起,以创建更复杂的对象或数据结构。
应用场景
Used in when you have an existing class or interface that does not meet the requirements you need. In this case, adapter can act as a bridge.
For exmple,
- Third-party library integration
- Multiple database accessors
行为型模式
如何协作一组对象应该来完成一个整体任务
观察者模式
Observer Pattern: 定义对象间的一对多的依赖关系 (a one to many dependency),当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
例子 🌰
假设一个电商网站
Store
,有多种 Product
(商品),同时,Customer
(消费者)和 Admin
(管理员)对商品上架、价格改变都感兴趣,希望能第一时间获得通知。上述问题的本质是
Store
希望发送通知给那些关心 Product
的对象,但 Store
并不想知道这些人是谁。观察者模式就是要分离被观察者和观察者之间的耦合关系。Store
不能直接引用Customer
和Admin
- 它引用
ProductObserver
接口,任何人想要观察Store
,只要实现该接口,并且把自己注册到Store
即可
最后将观察者的定义放到客户端
应用场景
When a specific event occurs you have a set of objects that need to be notified, without making assumption about who these objects are.
For example, event listening programming in Web: a button click, a key press, or a network message.