设计模式是软件开发中针对反复出现的问题总结归纳出的通用解决方案,掌握设计模式可以帮助开发者提高代码的可维护性、可扩展性和可复用性。本文将以 Java 语言为例,详细介绍常见的设计模式。
创建型设计模式主要用于对象的创建过程,封装对象的创建细节,使代码在创建对象时更加灵活和可维护。
确保一个类只有一个实例,并提供全局访问点。
实现方式:
public class Singleton {
// 静态变量存储唯一实例
private static Singleton instance;
// 私有化构造函数,防止外部实例化
private Singleton() {}
// 提供获取实例的方法
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
应用场景:日志记录器、数据库连接池等,这些场景中只需要一个实例来管理资源或进行操作。
定义一个创建对象的接口,让子类决定实例化哪个类。
实现方式:
// 产品接口
interface Product {
void use();
}
// 具体产品A
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 工厂类
class Factory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
应用场景:根据不同的配置或条件创建不同类型的对象,如根据用户输入创建不同的图形对象。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
实现方式:
// 抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 产品A接口
interface ProductA {
void operationA();
}
// 产品B接口
interface ProductB {
void operationB();
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体产品A1
class ConcreteProductA1 implements ProductA {
@Override
public void operationA() {
System.out.println("执行产品A1的操作");
}
}
// 具体产品B1
class ConcreteProductB1 implements ProductB {
@Override
public void operationB() {
System.out.println("执行产品B1的操作");
}
}
应用场景:创建一系列相互关联的对象,如创建不同操作系统下的图形界面组件。
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
实现方式:
// 产品类
class Computer {
private String cpu;
private String memory;
private String hardDisk;
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setMemory(String memory) {
this.memory = memory;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
", hardDisk='" + hardDisk + '\'' +
'}';
}
}
// 建造者类
class ComputerBuilder {
private Computer computer = new Computer();
public ComputerBuilder setCpu(String cpu) {
computer.setCpu(cpu);
return this;
}
public ComputerBuilder setMemory(String memory) {
computer.setMemory(memory);
return this;
}
public ComputerBuilder setHardDisk(String hardDisk) {
computer.setHardDisk(hardDisk);
return this;
}
public Computer build() {
return computer;
}
}
应用场景:创建复杂对象,如汽车、房屋等,这些对象的构建过程可能包含多个步骤和不同的配置选项。
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
实现方式:
class Prototype implements Cloneable {
private String name;
public Prototype(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
应用场景:创建对象的成本较高,且对象之间的差异较小,可以通过复制原型来创建新对象,如游戏中的角色克隆。
结构型设计模式主要用于处理类或对象的组合,通过将类或对象组合成更大的结构,以实现更复杂的功能。
为其他对象提供一种代理以控制对这个对象的访问。
实现方式:
// 抽象主题接口
interface Subject {
void request();
}
// 真实主题类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("执行真实请求");
}
}
// 代理类
class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
// 可以在调用真实主题的方法前后添加额外的逻辑
System.out.println("代理预处理");
realSubject.request();
System.out.println("代理后处理");
}
}
应用场景:远程代理(如远程方法调用)、虚拟代理(如延迟加载图片)、保护代理(如权限控制)等。
将一个类的接口转换成客户希望的另一个接口。
实现方式:
// 目标接口
interface Target {
void request();
}
// 被适配的类
class Adaptee {
public void specificRequest() {
System.out.println("执行特殊请求");
}
}
// 适配器类
class Adapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
应用场景:当需要使用一个现有的类,但它的接口与我们的需求不匹配时,可以使用适配器模式进行转换。
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
实现方式:
// 实现者接口
interface Implementor {
void operation();
}
// 具体实现者A
class ConcreteImplementorA implements Implementor {
@Override
public void operation() {
System.out.println("具体实现A的操作");
}
}
// 抽象类
abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 具体抽象类
class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
implementor.operation();
}
}
应用场景:当一个类存在两个独立变化的维度(如颜色和形状),且需要分别对这两个维度进行扩展时,可以使用桥接模式。
动态地给一个对象添加一些额外的职责。
实现方式:
// 抽象组件类
abstract class Component {
public abstract void operation();
}
// 具体组件类
class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("执行具体组件的操作");
}
}
// 抽象装饰器类
abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
}
// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
component.operation();
System.out.println("添加装饰A的操作");
}
}
应用场景:在不改变现有类结构的情况下,为对象添加新的功能,如为文件输入流添加缓冲功能。
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
实现方式:
// 子系统A类
class SubSystemA {
public void operationA() {
System.out.println("子系统A的操作");
}
}
// 子系统B类
class SubSystemB {
public void operationB() {
System.out.println("子系统B的操作");
}
}
// 外观类
class Facade {
private SubSystemA subsystemA;
private SubSystemB subsystemB;
public Facade() {
subsystemA = new SubSystemA();
subsystemB = new SubSystemB();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
}
}
应用场景:简化复杂子系统的接口,使客户端可以更方便地使用子系统,如在开发一个游戏时,将音频、图形等子系统封装在一个外观类中。
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
实现方式:
// 抽象组件类
abstract class ComponentTreeNode {
protected String name;
public ComponentTreeNode(String name) {
this.name = name;
}
public abstract void add(ComponentTreeNode component);
public abstract void remove(ComponentTreeNode component);
public abstract void display(int depth);
}
// 叶子节点类
class Leaf extends ComponentTreeNode {
public Leaf(String name) {
super(name);
}
@Override
public void add(ComponentTreeNode component) {
System.out.println("叶子节点不能添加子节点");
}
@Override
public void remove(ComponentTreeNode component) {
System.out.println("叶子节点不能删除子节点");
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
}
}
// 组合节点类
class Composite extends ComponentTreeNode {
private java.util.ArrayList<ComponentTreeNode> children = new java.util.ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(ComponentTreeNode component) {
children.add(component);
}
@Override
public void remove(ComponentTreeNode component) {
children.remove(component);
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
for (ComponentTreeNode component : children) {
component.display(depth + 1);
}
}
}
应用场景:处理具有层次结构的对象,如文件系统、组织结构等。
运用共享技术有效地支持大量细粒度的对象。
实现方式:
// 享元类
class Flyweight {
private String intrinsicState;
public Flyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
public void operation(String extrinsicState) {
System.out.println("内部状态: " + intrinsicState + ", 外部状态: " + extrinsicState);
}
}
// 享元工厂类
class FlyweightFactory {
private java.util.HashMap<String, Flyweight> flyweights = new java.util.HashMap<>();
public Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new Flyweight(key));
}
return flyweights.get(key);
}
}
应用场景:当需要创建大量相似对象,且这些对象的内部状态可以共享时,可以使用享元模式,如游戏中的大量子弹、敌人等对象。
行为型设计模式主要用于处理对象之间的交互和职责分配,使系统中的对象能够更好地协作和通信。
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
实现方式:
// 策略接口
interface Strategy {
void execute();
}
// 具体策略A
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("执行策略A");
}
}
// 上下文类
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
应用场景:根据不同的条件或需求选择不同的算法,如在电商系统中根据不同的促销策略计算商品的价格。
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
实现方式:
// 抽象类
abstract class AbstractClass {
public final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
}
protected abstract void primitiveOperation1();
protected abstract void primitiveOperation2();
}
// 具体类
class ConcreteClass extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("执行具体操作1");
}
@Override
protected void primitiveOperation2() {
System.out.println("执行具体操作2");
}
}
应用场景:在多个子类中存在相同的算法结构,但某些步骤的实现不同时,可以使用模板方法模式,如在不同的游戏关卡中,游戏的基本流程相同,但具体的任务和场景不同。
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
实现方式:
// 观察者接口
interface Observer {
void update(String message);
}
// 具体观察者类
class ConcreteObserver implements Observer {
@Override
public void update(String message) {
System.out.println("收到通知: " + message);
}
}
// 被观察的主题类
class Subject {
private java.util.ArrayList<Observer> observers = new java.util.ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
应用场景:当一个对象的状态变化需要通知其他多个对象时,可以使用观察者模式,如股票价格的变化通知所有关注该股票的用户。
提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
实现方式:
// 迭代器接口
interface Iterator {
boolean hasNext();
Object next();
}
// 具体迭代器类
class ConcreteIterator implements Iterator {
private java.util.ArrayList<Object> list;
private int index = 0;
public ConcreteIterator(java.util.ArrayList<Object> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Object next() {
if (hasNext()) {
return list.get(index++);
}
return null;
}
}
// 聚合类
class Aggregate {
private java.util.ArrayList<Object> list = new java.util.ArrayList<>();
public void add(Object item) {
list.add(item);
}
public Iterator createIterator() {
以下是继续为你整理完成的行为型设计模式以及对整个设计模式学习文档的总结部分:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
实现方式:
// 抽象处理者类
abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(int request);
}
// 具体处理者1
class ConcreteHandler1 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 0 && request < 10) {
System.out.println("处理者1处理请求: " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
// 具体处理者2
class ConcreteHandler2 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("处理者2处理请求: " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
应用场景:在审批流程中,不同级别的审批人按照一定顺序对请求进行处理;或者在日志处理中,不同级别的日志处理器(如 debug、info、error 等)依次处理日志消息。
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
实现方式:
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令类
class ConcreteCommand implements Command {
private Receiver receiver;
private String stateBeforeExecute;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
stateBeforeExecute = receiver.getState();
receiver.action();
}
@Override
public void undo() {
receiver.setState(stateBeforeExecute);
}
}
// 接收者类
class Receiver {
private String state;
public Receiver(String state) {
this.state = state;
}
public void action() {
state = "执行操作后的状态";
System.out.println("执行接收者的操作,状态变为: " + state);
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
// 调用者类
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
public void undoCommand() {
command.undo();
}
}
应用场景:在文本编辑器中,撤销和重做操作可以通过命令模式来实现;游戏中的操作记录和回放功能也可以使用命令模式进行设计。
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。
实现方式:
// 备忘录类
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 原发器类
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
state = memento.getState();
}
}
// 负责人类
class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
应用场景:在游戏中保存和恢复游戏进度;在编辑器中保存和恢复文档的历史版本。
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
实现方式:
// 状态接口
interface State {
void handle(Context context);
}
// 具体状态A
class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("状态A处理");
context.setState(new ConcreteStateB());
}
}
// 具体状态B
class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("状态B处理");
context.setState(new ConcreteStateA());
}
}
// 上下文类
class Context {
private State state;
public Context() {
state = new ConcreteStateA();
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
应用场景:在电梯控制系统中,电梯根据不同的状态(如运行、停止、开门、关门等)执行不同的操作;在游戏角色的状态管理中,角色根据不同的状态(如正常、受伤、死亡等)有不同的行为表现。
表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
实现方式:
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素A
class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public String operationA() {
return "具体元素A的操作";
}
}
// 具体元素B
class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public String operationB() {
return "具体元素B的操作";
}
}
// 访问者接口
interface Visitor {
void visitConcreteElementA(ConcreteElementA element);
void visitConcreteElementB(ConcreteElementB element);
}
// 具体访问者
class ConcreteVisitor implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println("访问者访问具体元素A,执行操作: " + element.operationA());
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println("访问者访问具体元素B,执行操作: " + element.operationB());
}
}
应用场景:在编译器中,对抽象语法树的不同节点(如表达式节点、语句节点等)进行语义分析、代码生成等操作;在图形系统中,对不同类型的图形元素(如圆形、矩形等)进行绘制、缩放等操作。
设计模式是软件开发中的宝贵经验总结,通过合理运用设计模式,可以提高代码的质量和可维护性,降低系统的复杂度。
在实际开发中,需要根据具体的需求和场景选择合适的设计模式,并灵活运用它们来解决问题。同时,理解设计模式的原理和思想,有助于培养良好的编程习惯和设计思维。
希望这份学习文档能够帮助你更好地理解和掌握设计模式,在软件开发中运用自如。