设计模式是一种编码规范,笔者认为不同的设计模式没有对错好坏之分,只有是否符合当前项目的实际情况,所以这篇文章中重在了解其思想。对于不同的设计模式,笔者留意的重点也有所不同。这主要是基于我以往接触项目时的体会。有的能解决我过去的疑问,就多写一些,有的似乎还没有用到过,就简单略过。
(图源维基百科)
一共有23种经典设计模式,分为创建型、结构型、行为型三类。以下先介绍这些模式中大多用到的基本原则。
七大原则
可以理解为类的六大原则+合成复用原则(尽量使用对象的组合或聚合而非继承)
- 单一职责
一个类只做一件事情
- 依赖倒置
- 高层次的模块不依赖于低层次模块,两者都依赖于抽象
- 具体实现依赖于抽象
- 里式替换
子类对象可 替换(是覆盖而不是修改) 父类对象,而不影响父类固有的功能。 它是下述开放封闭原则的基础。
- 开放封闭
对象或实体对扩展开放,对修改封闭
- 接口隔离
使用多个专门接口比使用单个总接口要好
- 迪米特法则(最少知识原则)
一个模块或对象应尽可能少地和其他对象或对象发生相互作用
接下来列举几个常用的设计模式。
单例模式
- 含义:保证整个应用程序的生命周期中,任意时刻,单个类的实例都最多只存在一个
- 应用场景:有真正的单一实例需求
- 例子:打印机打印程序
工厂模式
- 基本思想:实例化有大量公共接口的类,并动态决定将哪一个类实例化。
- 使用场景: 维基百科是这么写的:
The Factory Method design pattern solves problems like:
- How can an object be created so that subclasses can redefine which class to instantiate?
- How can a class defer instantiation to subclasses?
笔者认为可理解为:延迟实例化。
- 分类:简单工厂模式;工厂方法模式;抽象工厂模式
简单工厂模式
工厂类根据给定参数返回可能产品的类的示例,通常返回的类都有一个公共的父类和公共的方法。
工厂方法模式
以下是维基百科中提供的示例代码,通俗易懂。MazeGame就是其中的工厂类。
public abstract class Room {
abstract void connect(Room room);
}
public class MagicRoom extends Room {
public void connect(Room room) {}
}
public class OrdinaryRoom extends Room {
public void connect(Room room) {}
}
public abstract class MazeGame {
private final List<Room> rooms = new ArrayList<>();
public MazeGame() {
Room room1 = makeRoom();
Room room2 = makeRoom();
room1.connect(room2);
rooms.add(room1);
rooms.add(room2);
}
abstract protected Room makeRoom();
}
public class MagicMazeGame extends MazeGame {
@Override
protected MagicRoom makeRoom() {
return new MagicRoom();
}
}
public class OrdinaryMazeGame extends MazeGame {
@Override
protected OrdinaryRoom makeRoom() {
return new OrdinaryRoom();
}
}
MazeGame ordinaryGame = new OrdinaryMazeGame();
MazeGame magicGame = new MagicMazeGame();
抽象工厂模式
以下是Python示例代码:
from abc import ABC, abstractmethod
from sys import platform
class Button(ABC):
@abstractmethod
def paint(self):
pass
class LinuxButton(Button):
def paint(self):
return "Render a button in a Linux style"
class WindowsButton(Button):
def paint(self):
return "Render a button in a Windows style"
class MacOSButton(Button):
def paint(self):
return "Render a button in a MacOS style"
class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
class LinuxFactory(GUIFactory):
def create_button(self):
return LinuxButton()
class WindowsFactory(GUIFactory):
def create_button(self):
return WindowsButton()
class MacOSFactory(GUIFactory):
def create_button(self):
return MacOSButton()
if platform == "linux":
factory = LinuxFactory()
elif platform == "darwin":
factory = MacOSFactory()
elif platform == "win32":
factory = WindowsFactory()
else:
raise NotImplementedError(f"Not implemented for your platform: {platform}")
button = factory.create_button()
result = button.paint()
print(result)
也可以将类本身作为工厂:
from abc import ABC, abstractmethod
from sys import platform
class Button(ABC):
@abstractmethod
def paint(self):
pass
class LinuxButton(Button):
def paint(self):
return "Render a button in a Linux style"
class WindowsButton(Button):
def paint(self):
return "Render a button in a Windows style"
class MacOSButton(Button):
def paint(self):
return "Render a button in a MacOS style"
if platform == "linux":
factory = LinuxButton
elif platform == "darwin":
factory = MacOSButton
elif platform == "win32":
factory = WindowsButton
else:
raise NotImplementedError(f"Not implemented for your platform: {platform}")
button = factory()
result = button.paint()
print(result)
适配器模式
含义:将一个类的接口转化成另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能一起工作。
观察者模式(发布-订阅模式)
- 应用场景:维基百科中是这样写的:
The observer pattern addresses the following problems:
- A one-to-many dependency between objects should be defined without making the objects tightly coupled.
- When one object changes state, an open-ended number of dependent objects should be updated automatically.
- An object can notify multiple other objects.
- 个人理解:a不必和b强关联,但是a做了什么b可以立即知道;同理,不仅是b,还可以是bcd...,它们都可看做是一个“观察者”。
- 示例代码:
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;
interface Observer {
void update(String event);
}
class EventSource {
List<Observer> observers = new ArrayList<>();
void notifyObservers(String event) {
observers.forEach(observer -> observer.update(event));
}
void addObserver(Observer observer) {
observers.add(observer);
}
void scanSystemIn() {
var scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
notifyObservers(line);
}
}
}
public class ObserverDemo {
public static void main(String[] args) {
System.out.println("Enter Text : ");
var eventSource = new EventSource();
eventSource.addObserver(event -> {
System.out.println("Received response: " + event);
});
eventSource.scanSystemIn();
}
}
测试结果如下:
参考资料
- 维基百科
- Java程序员笔试面试宝典