23种设计模式全解析:优雅地编写高质量的代码(java)
大家好!欢迎来到“星辰编程理财”,今天为大家详细介绍23种设计模式,并通过实际示例代码演示它们的用法和优缺点。
设计模式介绍
定义和作用
设计模式是一套经过验证的、可复用的解决方案,用于解决软件设计中常见问题。它们是在特定情境中,根据面向对象设计原则,通过抽象和重组类和对象的方式来解决问题。
设计模式有助于提高代码的可读性、可维护性和可扩展性,同时还能够降低代码的耦合度,使代码更加灵活和可重用。
历史和发展
设计模式最早是由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides于1994年合著的《设计模式:可复用面向对象软件的基础》一书中提出。该书介绍了23种经典的设计模式,分为创建型、结构型和行为型三大类。
随着软件开发领域的不断发展,越来越多的设计模式被提出并应用于实际项目中。同时,一些新的设计原则和最佳实践也被纳入到设计模式中,以适应不断变化的需求和技术。
设计模式的原则和注意事项
SOLID原则
SOLID原则是面向对象设计的五个基本原则,它们是:
- 单一职责原则(Single Responsibility Principle):一个类应该只有一个引起变化的原因。
- 开闭原则(Open-Closed Principle):软件实体应该对扩展开放,对修改关闭。
- 里氏替换原则(Liskov Substitution Principle):所有引用基类的地方必须能够透明地使用其子类的对象。
- 接口隔离原则(Interface Segregation Principle):客户端不应该依赖它不需要的接口。
- 依赖倒置原则(Dependency Inversion Principle):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
遵循这些原则有助于设计出更加灵活、可维护和可扩展的代码。
设计模式的适用性和局限性
设计模式并不是万能的,它们适用于特定的问题和情境。在使用设计模式时,需要考虑以下几点:
- 问题的复杂性:设计模式适用于解决复杂的问题,对于简单的问题可能会增加代码的复杂性。
- 需求的变化:如果需求可能频繁变化,设计模式可以提供灵活性和可扩展性。
- 团队的熟悉程度:设计模式需要团队成员对其有一定的了解和掌握,否则可能会导致误用或滥用。
设计模式的发展趋势和最佳实践
随着软件开发技术的不断发展,设计模式也在不断演化和完善。一些新的设计模式正在被提出,以适应新的技术和需求,例如微服务架构中的设计模式。
同时,一些最佳实践也在不断涌现,以帮助开发人员更好地使用设计模式。例如,使用依赖注入来实现松耦合和可测试性,使用领域驱动设计来实现高内聚和可维护性等。
创建型模式
工厂模式
工厂模式是一种用于创建对象的创建型设计模式。它将对象的创建逻辑封装在一个工厂类中,客户端通过调用工厂类的方法来创建对象。
优点:
- 将对象的创建与使用分离,客户端只需要关心接口而不需要关心具体实现。
- 可以根据需要创建不同类型的对象,符合开闭原则。
缺点:
- 增加了代码的复杂性,需要额外定义工厂类和产品类。
代码示例:
public interface Product {
void operation();
}
public class ConcreteProduct implements Product {
@Override
public void operation() {
System.out.println("ConcreteProduct operation");
}
}
public interface Factory {
Product createProduct();
}
public class ConcreteFactory implements Factory {
@Override
public Product createProduct() {
return new ConcreteProduct();
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.operation();
}
}
抽象工厂模式
抽象工厂模式是一种用于创建一组相关或相互依赖对象的创建型设计模式。它提供一个接口,用于创建一系列具有相同接口的对象。
优点:
- 将对象的创建与使用分离,客户端只需要关心接口而不需要关心具体实现。
- 可以创建一系列相关的对象,保证了对象之间的一致性。
缺点:
- 增加了代码的复杂性,需要额外定义工厂类和产品类。
代码示例:
public interface AbstractProductA {
void operationA();
}
public class ConcreteProductA1 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA1 operationA");
}
}
public class ConcreteProductA2 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA2 operationA");
}
}
public interface AbstractProductB {
void operationB();
}
public class ConcreteProductB1 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB1 operationB");
}
}
public class ConcreteProductB2 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB2 operationB");
}
}
public interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
public class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory factory = new ConcreteFactory1();
AbstractProductA productA = factory.createProductA();
AbstractProductB productB = factory.createProductB();
productA.operationA();
productB.operationB();
}
}
单例模式
单例模式是一种只能创建一个实例的创建型设计模式。它提供了一种全局访问实例的方式,保证了在程序中只有一个实例存在。
优点:
- 保证了在程序中只有一个实例存在,避免了资源的浪费。
- 提供了对唯一实例的全局访问方式。
缺点:
- 破坏了类的封装性,因为单例类的构造函数必须是私有的。
- 可能引起线程安全问题,需要在实现时进行考虑。
代码示例:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Client {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
}
}
原型模式
原型模式是一种通过复制现有对象来创建新对象的创建型设计模式。它通过克隆来创建对象,而不是使用构造函数。
优点:
- 提高了对象的创建效率,避免了重复创建对象。
- 可以动态地添加或删除对象。
缺点:
- 需要实现Cloneable接口,并覆盖clone()方法。
- 克隆的对象和原始对象共享相同的引用,可能会引发问题。
代码示例:
public abstract class Prototype implements Cloneable {
public abstract Prototype clone();
}
public class ConcretePrototype extends Prototype {
private int value;
public ConcretePrototype(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public Prototype clone() {
return new ConcretePrototype(value);
}
}
public class Client {
public static void main(String[] args) {
Prototype prototype = new ConcretePrototype(10);
Prototype clone = prototype.clone();
System.out.println(clone.getValue());
}
}
建造者模式
建造者模式是一种用于创建复杂对象的创建型设计模式。它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
优点:
- 将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
- 简化了对象的构建过程,使得客户端不需要知道具体的构建细节。
缺点:
- 增加了代码的复杂性,需要定义多个类和接口。
代码示例:
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
System.out.println("partA: " + partA);
System.out.println("partB: " + partB);
System.out.println("partC: " + partC);
}
}
public abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public Product getResult() {
return product;
}
}
public class ConcreteBuilder extends Builder {
@Override
public void buildPartA() {
product.setPartA("partA");
}
@Override
public void buildPartB() {
product.setPartB("partB");
}
@Override
public void buildPartC() {
product.setPartC("partC");
}
}
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getResult();
product.show();
}
}
结构型模式
适配器模式
适配器模式是一种将一个类的接口转换成客户端所期望的另一个接口的结构型设计模式。它通过将客户端和目标接口之间的适配器,使得原本不兼容的类可以一起工作。
优点:
- 将不兼容的接口转换为兼容的接口,使得原本不兼容的类可以一起工作。
- 提高了代码的复用性,避免了修改已有代码。
缺点:
- 增加了代码的复杂性,需要定义适配器类。
代码示例:
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee specificRequest");
}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
桥接模式
桥接模式是一种将抽象和实现解耦的结构型设计模式。它将抽象和实现部分分离,使它们可以独立变化。
优点:
- 将抽象和实现部分分离,使它们可以独立变化。
- 提高了代码的可扩展性和可维护性。
缺点:
- 增加了代码的复杂性,需要定义抽象类和实现类。
代码示例:
public interface Implementor {
void operationImpl();
}
public class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorA operationImpl");
}
}
public class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorB operationImpl");
}
}
public abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
implementor.operationImpl();
}
}
public class Client {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Abstraction abstractionA = new RefinedAbstraction(implementorA);
abstractionA.operation();
Implementor implementorB = new ConcreteImplementorB();
Abstraction abstractionB = new RefinedAbstraction(implementorB);
abstractionB.operation();
}
}
装饰器模式
装饰器模式是一种动态地向对象添加新功能的结构型设计模式。它通过将对象包装在装饰器中,以增加对象的功能。
优点:
- 动态地向对象添加新功能,避免了使用继承的复杂性。
- 可以在运行时添加和删除对象的功能,提高了代码的灵活性。
缺点:
- 增加了代码的复杂性,需要定义装饰器类。
代码示例:
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorA operation");
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorB operation");
}
}
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();
}
}
组合模式
组合模式是一种将对象组合成树形结构以表示"部分-整体"的层次结构的结构型设计模式。它使得客户端可以统一处理单个对象和组合对象。
优点:
- 将对象组合成树形结构,使得客户端可以统一处理单个对象和组合对象。
- 可以方便地增加和修改对象的结构。
缺点:
- 增加了代码的复杂性,需要定义组合类和叶子类。
代码示例:
import java.util.ArrayList;
import java.util.List;
public interface Component {
void operation();
}
public class Leaf implements Component {
@Override
public void operation() {
System.out.println("Leaf operation");
}
}
public class Composite implements Component {
private List<Component> components = new ArrayList<>();
public void addComponent(Component component) {
components.add(component);
}
public void removeComponent(Component component) {
components.remove(component);
}
@Override
public void operation() {
for (Component component : components) {
component.operation();
}
}
}
public class Client {
public static void main(String[] args) {
Component leaf1 = new Leaf();
Component leaf2 = new Leaf();
Component composite1 = new Composite();
Component composite2 = new Composite();
composite1.addComponent(leaf1);
composite1.addComponent(leaf2);
composite2.addComponent(composite1);
composite2.operation();
}
}
外观模式
外观模式是一种为子系统中的一组接口提供一个统一接口的结构型设计模式。它定义了一个高层接口,使得子系统更加易于使用。
优点:
- 提供了一个统一的接口,使得子系统更加易于使用。
- 隐藏了子系统的复杂性,提高了客户端的可维护性。
缺点:
- 增加了代码的复杂性,需要定义外观类。
代码示例:
public class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operationA");
}
}
public class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operationB");
}
}
public class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operationC");
}
}
public class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
subsystemC = new SubsystemC();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
享元模式
享元模式是一种通过共享对象来有效支持大量细粒度对象的结构型设计模式。它通过共享相同的对象,以减少内存使用和提高性能。
优点:
- 减少了内存使用和提高了性能,通过共享相同的对象。
- 对象可以被复用,提高了代码的复用性。
缺点:
- 增加了代码的复杂性,需要定义享元类和工厂类。
代码示例:
import java.util.HashMap;
import java.util.Map;
public interface Flyweight {
void operation();
}
public class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation() {
System.out.println("ConcreteFlyweight operation, intrinsicState: " + intrinsicState);
}
}
public class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new ConcreteFlyweight(key));
}
return flyweights.get(key);
}
}
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.getFlyweight("key1");
Flyweight flyweight2 = factory.getFlyweight("key2");
Flyweight flyweight3 = factory.getFlyweight("key1");
flyweight1.operation();
flyweight2.operation();
flyweight3.operation();
}
}
代理模式
代理模式是一种为其他对象提供一个代理或占位符以控制对这个对象的访问的结构型设计模式。它通过使用代理类来控制对原始对象的访问。
优点:
- 可以通过代理类来控制对原始对象的访问。
- 可以增加额外的功能,例如权限验证、延迟加载等。
缺点:
- 增加了代码的复杂性,需要定义代理类。
代码示例:
// 定义一个接口
interface Image {
void display();
}
// 真实的对象
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading image from disk: " + fileName);
}
public void display() {
System.out.println("Displaying image: " + fileName);
}
}
// 代理对象
class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
// 使用代理对象
public class Main {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display();
}
}
行为型模式
行为型模式主要关注对象之间的通信和协作方式,以及如何通过对象之间的交互来实现更灵活和可扩展的系统。下面我们将介绍几种常见的行为型设计模式,并给出相应的代码示例。
策略模式
策略模式定义了一系列的算法,并将每个算法封装起来,使它们可以互相替换。该模式使得算法的变化独立于使用算法的客户端。
优点:
- 策略模式可以减少代码的重复,避免大量的if-else语句。
- 策略模式可以提高代码的可维护性和可扩展性,新增一种策略只需要增加一个策略类即可。
缺点:
- 策略模式会增加系统中策略类的数量,可能会导致类的数量庞大。
代码示例:
// 定义策略接口
public interface Strategy {
void execute();
}
// 实现具体的策略类
public class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("执行策略A");
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("执行策略B");
}
}
// 定义上下文类
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
// 使用策略模式
public class Main {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategyA());
context.executeStrategy();
context = new Context(new ConcreteStrategyB());
context.executeStrategy();
}
}
观察者模式
观察者模式定义了对象之间一种一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新。
优点:
- 观察者模式可以实现对象之间的解耦,被观察者和观察者之间没有直接的引用依赖。
- 观察者模式可以动态地添加和删除观察者。
缺点:
- 观察者模式可能导致系统中观察者数量过多,增加了系统的复杂性。
代码示例:
// 定义观察者接口
public interface Observer {
void update();
}
// 实现具体的观察者类
public class ConcreteObserverA implements Observer {
@Override
public void update() {
System.out.println("观察者A收到通知并更新");
}
}
public class ConcreteObserverB implements Observer {
@Override
public void update() {
System.out.println("观察者B收到通知并更新");
}
}
// 定义被观察者类
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 使用观察者模式
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observerA = new ConcreteObserverA();
Observer observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
subject.notifyObservers();
}
}
责任链模式
责任链模式将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
优点:
- 责任链模式可以动态地组合和切换处理者。
- 责任链模式符合开闭原则,可以方便地扩展新的处理者。
缺点:
- 责任链模式可能导致请求的处理者不明确,某个请求可能没有被处理或者被多个处理者处理。
代码示例:
// 定义请求类
public class Request {
private String type;
public Request(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
// 定义处理者接口
public interface Handler {
void handleRequest(Request request);
}
// 实现具体的处理者类
public class ConcreteHandlerA implements Handler {
private Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (request.getType().equals("A")) {
System.out.println("处理请求A");
} else {
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
}
public class ConcreteHandlerB implements Handler {
private Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (request.getType().equals("B")) {
System.out.println("处理请求B");
} else {
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
}
// 使用责任链模式
public class Main {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
Request requestA = new Request("A");
Request requestB = new Request("B");
handlerA.handleRequest(requestA);
handlerA.handleRequest(requestB);
}
}
命令模式
命令模式将请求封装成一个对象,并将请求的发送者和接收者解耦,使得可以通过不同的请求对象来参数化其他对象。
优点:
- 命令模式将请求和处理分开,可以更加灵活地进行组合和扩展。
- 命令模式可以支持撤销和重做操作。
缺点:
- 命令模式可能导致类的数量庞大。
代码示例:
// 定义命令接口
public interface Command {
void execute();
}
// 实现具体的命令类
public class ConcreteCommandA implements Command {
private Receiver receiver;
public ConcreteCommandA(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.actionA();
}
}
public class ConcreteCommandB implements Command {
private Receiver receiver;
public ConcreteCommandB(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.actionB();
}
}
// 定义接收者类
public class Receiver {
public void actionA() {
System.out.println("执行操作A");
}
public void actionB() {
System.out.println("执行操作B");
}
}
// 定义调用者类
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 使用命令模式
public class Main {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command commandA = new ConcreteCommandA(receiver);
Command commandB = new ConcreteCommandB(receiver);
Invoker invokerA = new Invoker(commandA);
invokerA.executeCommand();
Invoker invokerB = new Invoker(commandB);
invokerB.executeCommand();
}
}
迭代器模式
迭代器模式提供了一种访问聚合对象中各个元素的方法,而不需要暴露聚合对象的内部表示。
优点:
- 迭代器模式将遍历算法和聚合对象分离,可以更灵活地定义和修改遍历算法。
- 迭代器模式可以对聚合对象进行多种方式的遍历。
缺点:
- 迭代器模式增加了系统的复杂性。
代码示例:
// 定义迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 定义具体的迭代器类
public class ConcreteIterator<T> implements Iterator<T> {
private List<T> list;
private int index;
public ConcreteIterator(List<T> list) {
this.list = list;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public T next() {
T element = list.get(index);
index++;
return element;
}
}
// 定义聚合对象类
public class Aggregate<T> {
private List<T> list;
public Aggregate(List<T> list) {
this.list = list;
}
public Iterator<T> createIterator() {
return new ConcreteIterator<>(list);
}
}
// 使用迭代器模式
public class Main {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Aggregate<Integer> aggregate = new Aggregate<>(list);
Iterator<Integer> iterator = aggregate.createIterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
System.out.println(element);
}
}
}
中介者模式
中介者模式定义了一个中介对象来封装一系列对象之间的交互,使得这些对象之间的交互通过中介者来实现,而不是直接相互引用。
优点:
- 中介者模式可以减少对象之间的直接依赖关系,使其耦合度降低。
- 中介者模式可以集中控制对象之间的交互逻辑,使系统更易于维护和扩展。
缺点:
- 中介者模式可能导致中介者对象变得复杂庞大。
代码示例:
// 定义中介者接口
public interface Mediator {
void sendMessage(String message, Colleague colleague);
}
// 实现具体的中介者类
public class ConcreteMediator implements Mediator {
private List<Colleague> colleagues;
public ConcreteMediator() {
this.colleagues = new ArrayList<>();
}
public void addColleague(Colleague colleague) {
colleagues.add(colleague);
}
@Override
public void sendMessage(String message, Colleague colleague) {
for (Colleague c : colleagues) {
if (c != colleague) {
c.receiveMessage(message);
}
}
}
}
// 定义同事类
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public void sendMessage(String message) {
mediator.sendMessage(message, this);
}
public abstract void receiveMessage(String message);
}
public class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
@Override
public void receiveMessage(String message) {
System.out.println("同事A收到消息:" + message);
}
}
public class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
@Override
public void receiveMessage(String message) {
System.out.println("同事B收到消息:" + message);
}
}
// 使用中介者模式
public class Main {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Colleague colleagueA = new ConcreteColleagueA(mediator);
Colleague colleagueB = new ConcreteColleagueB(mediator);
mediator.addColleague(colleagueA);
mediator.addColleague(colleagueB);
colleagueA.sendMessage("Hello, ColleagueB!");
colleagueB.sendMessage("Hi, ColleagueA!");
}
}
备忘录模式
备忘录模式提供了一种保存和恢复对象状态的方式,用于在不破坏封装的前提下保存对象的内部状态,并在需要时恢复到之前的状态。
优点:
- 备忘录模式可以实现对象状态的保存和恢复,不破坏封装。
- 备忘录模式可以简化原发器类,将状态保存和恢复的责任交给备忘录类。
缺点:
- 备忘录模式可能导致大量的备忘录对象产生,增加了系统的复杂性。
代码示例:
// 定义备忘录类
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 定义原发器类
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
}
// 定义负责人类
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
// 使用备忘录模式
public class Main {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State 1");
System.out.println("当前状态:" + originator.getState());
caretaker.setMemento(originator.createMemento());
originator.setState("State 2");
System.out.println("当前状态:" + originator.getState());
originator.restoreMemento(caretaker.getMemento());
System.out.println("恢复后的状态:" + originator.getState());
}
}
解释器模式
解释器模式定义了一种语言的文法表示,并定义了一个解释器来解释这个语言中的句子。
优点:
- 解释器模式可以扩展语言的规则,易于实现新的语言解释器。
- 解释器模式可以简化语法规则的表示和处理。
缺点:
- 解释器模式可能导致类的数量庞大,增加了系统的复杂性。
代码示例:
// 定义抽象表达式类
public interface Expression {
int interpret();
}
// 实现具体的表达式类
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
public class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
// 使用解释器模式
public class Main {
public static void main(String[] args) {
Expression expression = new AddExpression(
new NumberExpression(5),
new AddExpression(
new NumberExpression(3),
new NumberExpression(2)
)
);
int result = expression.interpret();
System.out.println("解释结果:" + result);
}
}
状态模式
状态模式允许一个对象在其内部状态改变时改变其行为,使其看起来好像改变了类。
优点:
- 状态模式将状态的判断和状态行为封装在不同的状态类中,使得状态的判断和状态行为可以独立变化。
- 状态模式可以简化复杂的条件判断语句,提高代码的可维护性和可读性。
缺点:
- 状态模式会增加系统中类的数量。
代码示例:
// 定义状态接口
public interface State {
void handle();
}
// 实现具体的状态类
public class ConcreteStateA implements State {
@Override
public void handle() {
System.out.println("处理状态A");
}
}
public class ConcreteStateB implements State {
@Override
public void handle() {
System.out.println("处理状态B");
}
}
// 定义上下文类
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
// 使用状态模式
public class Main {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request();
context.setState(new ConcreteStateB());
context.request();
}
}
模板方法模式
模板方法模式定义了一个算法的框架,将一些步骤的实现延迟到子类中,使得子类可以不改变算法的结构即可重新定义算法的某些步骤。
优点:
- 模板方法模式将算法的框架和具体的实现分离,使得算法的结构可以保持稳定,而具体的实现可以灵活变化。
- 模板方法模式可以提高代码的复用性。
缺点:
- 模板方法模式可能导致子类数目庞大。
代码示例:
// 定义抽象模板类
public abstract class AbstractTemplate {
public final void templateMethod() {
operation1();
operation2();
operation3();
}
protected abstract void operation1();
protected abstract void operation2();
protected abstract void operation3();
}
// 实现具体模板类
public class ConcreteTemplateA extends AbstractTemplate {
@Override
protected void operation1() {
System.out.println("具体模板A的操作1");
}
@Override
protected void operation2() {
System.out.println("具体模板A的操作2");
}
@Override
protected void operation3() {
System.out.println("具体模板A的操作3");
}
}
public class ConcreteTemplateB extends AbstractTemplate {
@Override
protected void operation1() {
System.out.println("具体模板B的操作1");
}
@Override
protected void operation2() {
System.out.println("具体模板B的操作2");
}
@Override
protected void operation3() {
System.out.println("具体模板B的操作3");
}
}
// 使用模板方法模式
public class Main {
public static void main(String[] args) {
AbstractTemplate templateA = new ConcreteTemplateA();
templateA.templateMethod();
AbstractTemplate templateB = new ConcreteTemplateB();
templateB.templateMethod();
}
}
访问者模式
访问者模式将数据结构和作用于结构上的操作解耦,使得可以在不改变数据结构的前提下定义作用于这些元素的新操作。
优点:
- 访问者模式将数据结构和操作分离,增加新的操作很容易。
- 访问者模式可以在不改变元素类的前提下定义新的操作。
缺点:
- 访问者模式增加了系统的复杂性。
代码示例:
// 定义一个访问者接口
interface Visitor {
void visit(ElementA element);
void visit(ElementB element);
}
// 定义一个元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体的元素类A
class ElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationA() {
System.out.println("ElementA operationA");
}
}
// 具体的元素类B
class ElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationB() {
System.out.println("ElementB operationB");
}
}
// 具体的访问者类
class ConcreteVisitor implements Visitor {
@Override
public void visit(ElementA element) {
element.operationA();
}
@Override
public void visit(ElementB element) {
element.operationB();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitor = new ConcreteVisitor();
elementA.accept(visitor); // Output: ElementA operationA
elementB.accept(visitor); // Output: ElementB operationB
}
}