网站套餐网页,网站域名怎么进行实名认证,义乌手工活外发加工网160网,北京互联网公司排行榜目录
一、概述
1. 创建型模式(5种)
2. 结构型模式(7种)
3. 行为型模式(11种)
二、代码示例说明
1.单例模式#xff08;Singleton#xff09;
2.工厂方法模式(Factory Method)
3.抽象工厂模式(Abstract Factory)
4.建造者模式(Builder)
5.原型模式 (Prototype)
6.适…目录
一、概述
1. 创建型模式(5种)
2. 结构型模式(7种)
3. 行为型模式(11种)
二、代码示例说明
1.单例模式Singleton
2.工厂方法模式(Factory Method)
3.抽象工厂模式(Abstract Factory)
4.建造者模式(Builder)
5.原型模式 (Prototype)
6.适配器模式(Adapter)
7.桥接模式(Bridge)
8.组合模式(Composite)
9.装饰器模式(Decorator
10.外观模式(Facade)
11.享元模式(Flyweight)
12.代理模式(Proxy)
13.策略模式(Strategy)
14.模板方法模式Template Method
15.观察者模式(Observer)
16.迭代器模式(Iterator)
17.责任链模式(Chain of Responsibility)
18.命令模式(Command)
19.备忘录模式(Memento) 一、概述
Java开发中的设计模式是软件工程中用于解决常见问题的一系列最佳实践。这些设计模式并不是Java特有的但它们与Java等面向对象编程语言结合得非常好因为设计模式本质上就是面向对象设计原则的具体化。
设计模式主要分为三大类创建型模式、结构型模式和行为型模式。下面简要介绍每一类中的一些常见设计模式及其在Java开发中的应用。
1. 创建型模式(5种)
创建型模式主要关注对象的创建过程。 单例模式Singleton确保一个类只有一个实例并提供一个全局访问点。常用于配置例如文件的读取、数据库连接等。 工厂方法模式Factory Method定义一个用于创建对象的接口但让子类决定要实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 抽象工厂模式Abstract Factory提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。 建造者模式Builder将一个复杂对象的构建与它的表示分离使得同样的构建过程可以创建不同的表示。 原型模式Prototype用原型实例指定创建对象的种类并通过拷贝这些原型创建新的对象。
2. 结构型模式(7种)
结构型模式关注类和对象的组合。 适配器模式Adapter将一个类的接口转换成客户端所期待的另一种接口形式使接口不兼容的类可以一起工作。 桥接模式Bridge将抽象部分与实现部分分离使它们都可以独立地变化。 组合模式Composite将对象组合成树形结构以表示“部分-整体”的层次结构组合模式使得用户对单个对象和组合对象的使用具有一致性。 装饰器模式Decorator动态地给一个对象添加一些额外的职责就增加功能来说装饰器模式相比生成子类更为灵活。 外观模式Facade为子系统中的一组接口提供一个一致的界面外观模式定义了一个高层接口这个接口使得这一子系统更加容易使用。 享元模式Flyweight运用共享技术有效地支持大量细粒度对象的复用。 代理模式Proxy为其他对象提供一种代理以控制对这个对象的访问。
3. 行为型模式(11种)
行为型模式关注对象之间的通信和职责分配。 策略模式Strategy定义了一系列的算法并将每一个算法封装起来使它们可以相互替换。 模板方法模式Template Method定义了一个操作中的算法的骨架而将一些步骤延迟到子类中实现。 观察者模式Observer定义了一种一对多的依赖关系让多个观察者对象同时监听某一个主题对象这个主题对象在状态发生变化时会通知所有观察者对象使它们能够自动更新自己。 迭代器模式Iterator提供一种方法顺序访问一个聚合对象中各个元素而又不需暴露该对象的内部表示。 责任链模式Chain of Responsibility为请求的发送者和接收者之间解耦使多个对象都有机会处理这个请求或者将这个请求传递到链上的下一个对象。 命令模式Command将一个请求封装为一个对象从而使我们可用不同的请求、队列、日志来参数化其他对象。 备忘录模式Memento在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态。 状态模式State允许一个对象在其内部状态改变时改变它的行为对象看起来似乎修改了它的类。 访问者模式Visitor表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 中介者模式Mediator用一个中介对象来封装一系列的对象交互中介者使各对象不需要显式地相互引用从而使其耦合松散而且可以独立地改变它们之间的交互。 解释器模式Interpreter给定一个语言定义它的文法的一种表示并定义一个解释器该解释器使用该表示来解释语言中的句子。
这些设计模式在Java开发中有着广泛的应用它们可以帮助开发者设计出更加灵活、可扩展和易于维护的软件系统。
二、代码示例说明
1.单例模式Singleton
懒汉式线程安全通过在getInstance()方法上添加synchronized关键字可以解决线程安全问题但会降低效率。 public class SingletonLazySafe { private static SingletonLazySafe instance; private SingletonLazySafe() {} public static synchronized SingletonLazySafe getInstance() { if (instance null) { instance new SingletonLazySafe(); } return instance; } } 饿汉式这种方式基于类加载机制避免了多线程同步问题但是实例在类装载时就完成创建没有达到Lazy Loading的效果 public class SingletonEager { private static final SingletonEager instance new SingletonEager(); private SingletonEager() {} public static SingletonEager getInstance() { return instance; } } 双重检查锁定 这种方式既实现了延迟加载又保证了线程安全但是需要注意instance变量必须声明为volatile类型。 public class SingletonDoubleChecked { // 使用volatile关键字保证多线程下的可见性和禁止指令重排序 private static volatile SingletonDoubleChecked instance; private SingletonDoubleChecked() {} public static SingletonDoubleChecked getInstance() { if (instance null) { synchronized (SingletonDoubleChecked.class) { if (instance null) { instance new SingletonDoubleChecked(); } } } return instance; } } 在实际应用中推荐使用饿汉式如果不需要延迟加载或双重检查锁定方式如果需要延迟加载。懒汉式线程安全虽然解决了线程安全问题但每次调用getInstance()时都进行同步影响性能。而双重检查锁定方式既保证了线程安全又避免了不必要的同步开销。
2.工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式它定义了一个创建对象的接口但让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。 // 定义一个产品接口 interface Product { void use(); } // 实现产品接口的具体产品类 class ConcreteProductA implements Product { Override public void use() { System.out.println(Using ConcreteProductA); } } class ConcreteProductB implements Product { Override public void use() { System.out.println(Using ConcreteProductB); } } // 定义一个创建产品对象的工厂接口 interface Creator { Product factoryMethod(); } // 实现工厂接口的类并具体指定返回的产品类型 class ConcreteCreatorA implements Creator { Override public Product factoryMethod() { return new ConcreteProductA(); } } class ConcreteCreatorB implements Creator { Override public Product factoryMethod() { return new ConcreteProductB(); } } // 客户端代码 public class FactoryMethodPatternDemo { public static void main(String[] args) { Creator creatorA new ConcreteCreatorA(); Product productA creatorA.factoryMethod(); productA.use(); Creator creatorB new ConcreteCreatorB(); Product productB creatorB.factoryMethod(); productB.use(); } } 在上面的代码中Product是一个产品接口ConcreteProductA和ConcreteProductB是实现了Product接口的具体产品类。Creator是一个工厂接口它声明了一个工厂方法factoryMethod()用于创建产品对象。ConcreteCreatorA和ConcreteCreatorB是实现了Creator接口的具体工厂类它们分别重写了factoryMethod()方法并返回了不同的具体产品实例。
在客户端代码中我们通过不同的工厂类来创建不同的产品对象并调用其use()方法。这样就实现了在运行时根据不同的工厂类来创建不同类型的产品对象这就是工厂方法模式的核心思想。
3.抽象工厂模式(Abstract Factory)
在抽象工厂模式中我们定义一个抽象工厂接口用于创建相关或依赖对象的家族但不指定具体类。每个生成的工厂类能够返回该工厂所创建的对象类型的具体实例。 // 定义一个产品接口A interface ProductA { void use(); } // 实现产品接口A的具体产品类 class ConcreteProductA1 implements ProductA { Override public void use() { System.out.println(Using ConcreteProductA1); } } class ConcreteProductA2 implements ProductA { Override public void use() { System.out.println(Using ConcreteProductA2); } } // 定义一个产品接口B interface ProductB { void eat(); } // 实现产品接口B的具体产品类 class ConcreteProductB1 implements ProductB { Override public void eat() { System.out.println(Eating ConcreteProductB1); } } class ConcreteProductB2 implements ProductB { Override public void eat() { System.out.println(Eating ConcreteProductB2); } } // 抽象工厂接口 interface AbstractFactory { ProductA createProductA(); ProductB createProductB(); } // 具体工厂类A class ConcreteFactoryA implements AbstractFactory { Override public ProductA createProductA() { return new ConcreteProductA1(); } Override public ProductB createProductB() { return new ConcreteProductB1(); } } // 具体工厂类B class ConcreteFactoryB implements AbstractFactory { Override public ProductA createProductA() { return new ConcreteProductA2(); } Override public ProductB createProductB() { return new ConcreteProductB2(); } } // 客户端代码 public class AbstractFactoryPatternDemo { public static void main(String[] args) { AbstractFactory factoryA new ConcreteFactoryA(); ProductA productA1 factoryA.createProductA(); productA1.use(); ProductB productB1 factoryA.createProductB(); productB1.eat(); AbstractFactory factoryB new ConcreteFactoryB(); ProductA productA2 factoryB.createProductA(); productA2.use(); ProductB productB2 factoryB.createProductB(); productB2.eat(); } } 在这个例子中我们定义了两个产品接口ProductA和ProductB以及它们的实现类。然后我们定义了一个抽象工厂接口AbstractFactory它包含两个方法createProductA()和createProductB()分别用于创建ProductA和ProductB类型的产品。接着我们定义了两个具体工厂类ConcreteFactoryA和ConcreteFactoryB它们实现了AbstractFactory接口并分别返回不同类型的产品实例
4.建造者模式(Builder)
建造者模式Builder Pattern是一种对象创建型设计模式它通过将复杂对象的构建与它的表示分离使得同样的构建过程可以创建不同的表示。建造者模式通常包含以下几个角色 Product产品角色被构建的复杂对象包含多个组成部件的类。 Builder抽象建造者为创建Product对象的各个部件指定抽象接口。 ConcreteBuilder具体建造者实现Builder接口构造和装配产品的各个部件定义并明确它所创建的表示并提供一个检索产品的接口。 Director指挥者构建一个使用Builder接口的对象。它主要是用于隔离客户与对象的生产过程并指导如何生成对象。 Client客户端向Director提供需求信息不直接参与产品的构建过程 // 产品角色 class Product { private String partA; private String partB; // 产品的组成部分 void setPartA(String partA) { this.partA partA; } void setPartB(String partB) { this.partB partB; } // 显示产品 void show() { System.out.println(Product Parts:); System.out.println(Part A: partA); System.out.println(Part B: partB); } } // 抽象建造者 interface Builder { void buildPartA(); void buildPartB(); Product getResult(); } // 具体建造者 class ConcreteBuilder implements Builder { private Product product new Product(); Override public void buildPartA() { product.setPartA(PartA); } Override public void buildPartB() { product.setPartB(PartB); } Override public Product getResult() { return product; } } // 指挥者 class Director { private Builder builder; public Director(Builder builder) { this.builder builder; } // 构造复杂对象 public void construct() { builder.buildPartA(); builder.buildPartB(); } } // 客户端 public class BuilderPatternDemo { public static void main(String[] args) { Builder builder new ConcreteBuilder(); Director director new Director(builder); director.construct(); Product product builder.getResult(); product.show(); } } 在这个例子中Product类是一个复杂对象它由两个部分组成PartA和PartB。Builder接口定义了构建复杂对象的接口而ConcreteBuilder类实现了这个接口并具体构建了Product对象。Director类负责指导如何构建Product对象它通过Builder接口与ConcreteBuilder类进行交互。最后在客户端代码中我们创建了Builder和Director对象并通过Director来构建Product对象。
5.原型模式 (Prototype)
在Java中原型模式Prototype Pattern通常涉及到对象的克隆。当我们需要从一个现有的对象创建一个新的、完全相同的对象时就可以使用原型模式。这通常通过实现Cloneable接口并重写Object类的clone()方法来完成。但是请注意clone()方法默认提供的是浅拷贝shallow copy它只复制对象本身和对象中的基本数据类型但不会复制对象中的引用类型指向的对象。为了实现深拷贝deep copy我们需要自己编写复制引用类型指向的对象的逻辑。
以下是一个使用原型模式的Java代码示例其中包含了浅拷贝和深拷贝的说明。我们将创建一个Person类该类包含基本数据类型和引用类型例如一个指向Address对象的引用。然后我们将展示如何实现这个类的浅拷贝和深拷贝。 // Address 类一个简单的引用类型 class Address { String street; String city; public Address(String street, String city) { this.street street; this.city city; } Override public String toString() { return Address{ street street \ , city city \ }; } } // Person 类实现了 Cloneable 接口以支持克隆 class Person implements Cloneable { String name; int age; Address address; // 引用类型 public Person(String name, int age, Address address) { this.name name; this.age age; this.address address; } // 浅拷贝方法 Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // 深拷贝方法 public Person deepClone() throws CloneNotSupportedException { Person cloned (Person) clone(); // 先进行浅拷贝 cloned.address (Address) address.clone(); // 但这里需要修正因为 Address 没有实现 Cloneable // 假设 Address 也实现了 Cloneable则上面的行将有效 // 但为了演示我们在这里手动复制 Address 对象 cloned.address new Address(address.street, address.city); return cloned; } Override public String toString() { return Person{ name name \ , age age , address address }; } // 注意这里我们假设 Address 类也实现了 Cloneable但实际上它没有。 // 在实际项目中如果 Address 或其他引用类型需要被深拷贝它们也应该实现 Cloneable。 } // 注意上面的代码中Address 类并没有实现 Cloneable 接口 // 因此直接调用 address.clone() 会导致编译错误。 // 为了简单起见我们在 deepClone 方法中通过构造函数手动复制了 Address 对象。 // 客户端代码 public class PrototypePatternDemo { public static void main(String[] args) throws CloneNotSupportedException { Address address new Address(123 Elm Street, Somewhere); Person original new Person(John Doe, 30, address); // 浅拷贝 Person shallowCloned (Person) original.clone(); System.out.println(Original Person:); System.out.println(original); System.out.println(Shallow Cloned Person:); System.out.println(shallowCloned); // 修改浅拷贝对象的 Address 的属性将看到原始对象的 Address 属性也被修改了 shallowCloned.address.street 456 Oak Street; System.out.println(\nModified Shallow Cloned Person:); System.out.println(shallowCloned); System.out.println(Original Person (affected by shallow clone):); System.out.println(original); // 深拷贝 Person deepCloned original.deepClone(); System.out.println(\nOriginal Person again:); System.out.println(original); System.out.println(Deep Cloned Person:); System.out.println(deepCloned); // 修改深拷贝对象的 Address 的属性原始对象不会受到影响 deepCloned.address.street 789 Pine Street; System.out.println(\nModified Deep Cloned Person:); System.out.println(deepCloned); System.out.println(Original Person (unaffected by deep clone): 6.适配器模式(Adapter)
适配器模式Adapter Pattern是一种结构型设计模式它允许一个接口通常是新的接口与不符合该接口要求的类通常是旧的类协同工作。在适配器模式中我们创建一个包装类即适配器该类负责接收客户端的请求然后将这些请求转换为被适配者Adaptee可以理解的请求并转发给被适配者。
以下是使用Java代码实现的适配器模式示例
假设我们有一个老式的电源插座TwoProngedOutlet它只能接受两个插头的电器TwoProngedDevice但现在我们有一个新的电器ThreeProngedDevice它有三个插头无法直接插入老式的电源插座中。为了解决这个问题我们可以创建一个适配器ThreeToTwoAdapter它将三个插头的电器转换为两个插头的电器以便能够插入老式的插座。
首先定义电器接口和两个具体的电器类 // 电器接口 interface Device { void connect(); } // 两个插头的电器 class TwoProngedDevice implements Device { Override public void connect() { System.out.println(Connecting two-pronged device.); } } // 三个插头的电器 class ThreeProngedDevice { public void plugInThreePronged() { System.out.println(Plugging in three-pronged device.); } } 然后定义适配器类该类继承自ThreeProngedDevice并实现Device接口 // 适配器类 class ThreeToTwoAdapter extends ThreeProngedDevice implements Device { Override public void connect() { // 调用三个插头的电器的方法并添加适配逻辑 // 在这里我们简单地模拟了适配过程 plugInThreePronged(); // 假设我们进行了某种适配操作使得ThreeProngedDevice能作为TwoProngedDevice使用 System.out.println(Adapting three-pronged device to two-pronged outlet.); } } 最后使用这些类来展示适配器模式的工作原理 public class AdapterPatternDemo { public static void main(String[] args) { // 创建一个老式的插座能接受的电器 Device twoProngedDevice new TwoProngedDevice(); twoProngedDevice.connect(); // 创建一个适配器让三个插头的电器能在老式插座上使用 Device threeProngedDeviceThroughAdapter new ThreeToTwoAdapter(); threeProngedDeviceThroughAdapter.connect(); // 适配器内部处理了转换 } } 在这个示例中ThreeToTwoAdapter类是一个适配器它使得原本不符合Device接口即只有两个插头的插座能接受的电器的ThreeProngedDevice类能够通过适配器的方式满足Device接口的要求从而可以在老式的插座上使用。这是适配器模式的一个典型应用场景。
7.桥接模式(Bridge) 桥接模式Bridge Pattern是一种结构型设计模式它将抽象部分与它的实现部分分离使它们都可以独立地变化。这种模式通常用于实现多层次的抽象结构其中每一层抽象都使用下一层抽象的实现来构建。
在Java中桥接模式通常通过组合关系来替代继承关系以减少类之间的耦合。以下是一个简单的Java代码示例展示了桥接模式的应用。
假设我们有一个绘图系统需要支持多种形状如圆形和矩形和多种颜色。我们可以使用桥接模式将形状和颜色分开使得它们可以独立地变化。
首先我们定义一个颜色接口Color和一个形状抽象类Shape并在形状类中持有一个颜色对象的引用。 // 颜色接口 interface Color { void applyColor(); } // 红色实现 class Red implements Color { Override public void applyColor() { System.out.println(Applying red color); } } // 蓝色实现 class Blue implements Color { Override public void applyColor() { System.out.println(Applying blue color); } } // 形状抽象类 abstract class Shape { protected Color color; public Shape(Color color) { this.color color; } public abstract void draw(); // 设置颜色 public void setColor(Color color) { this.color color; } // 应用颜色 public void applyColor() { color.applyColor(); } } // 圆形类 class Circle extends Shape { public Circle(Color color) { super(color); } Override public void draw() { applyColor(); System.out.println(Drawing Circle); } } // 矩形类 class Rectangle extends Shape { public Rectangle(Color color) { super(color); } Override public void draw() { applyColor(); System.out.println(Drawing Rectangle); } } // 客户端代码 public class BridgePatternDemo { public static void main(String[] args) { Shape redCircle new Circle(new Red()); Shape blueRectangle new Rectangle(new Blue()); redCircle.draw(); blueRectangle.draw(); // 修改矩形的颜色 blueRectangle.setColor(new Red()); blueRectangle.draw(); } } 在这个例子中Color接口和它的具体实现Red和Blue代表了颜色部分而Shape抽象类和它的具体实现Circle和Rectangle代表了形状部分。Shape类持有一个Color类型的引用这允许我们在运行时将形状与不同的颜色组合起来而不需要为每种颜色和形状的组合创建一个新的类。
通过桥接模式我们实现了抽象与实现的解耦使得系统的扩展变得更加容易。例如如果我们想要添加新的颜色或新的形状我们只需要创建新的颜色实现或形状类而不需要修改现有的代码。
8.组合模式(Composite)
组合模式Composite Pattern允许你将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式让客户端可以一致地处理单个对象和对象的组合。
在组合模式中我们通常会定义三个角色 Component抽象组件为组合中的对象声明接口在适当的情况下实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子组件。 Leaf叶子节点在组合中表示叶节点对象叶节点没有子节点。 Composite复合节点在组合中表示容器对象容器可以包含Component子类的实例。实现Component接口中用于管理子组件的方法。
下面是一个使用Java实现的简单组合模式示例我们将构建一个简单的文件系统包括文件夹Composite和文件Leaf // Component 接口 interface Component { void add(Component c); void remove(Component c); Component getChild(int i); void operation(); // 定义所有组件共有的行为 } // Leaf 类 class File implements Component { private String name; public File(String name) { this.name name; } Override public void add(Component c) { throw new UnsupportedOperationException(File cannot have children); } Override public void remove(Component c) { throw new UnsupportedOperationException(File cannot have children); } Override public Component getChild(int i) { throw new UnsupportedOperationException(File cannot have children); } Override public void operation() { System.out.println(File: name is processed.); } } // Composite 类 class Folder implements Component { private String name; private ListComponent children new ArrayList(); public Folder(String name) { this.name name; } Override public void add(Component c) { children.add(c); } Override public void remove(Component c) { children.remove(c); } Override public Component getChild(int i) { return children.get(i); } Override public void operation() { System.out.println(Folder: name is processed.); for (Component c : children) { c.operation(); } } } // 客户端代码 public class CompositePatternDemo { public static void main(String[] args) { Component root new Folder(root); Component folder1 new Folder(folder1); Component folder2 new Folder(folder2); Component file1 new File(file1.txt); Component file2 new File(file2.txt); root.add(folder1); root.add(folder2); folder1.add(file1); folder2.add(file2); // 遍历和打印所有组件 root.operation(); } } 在这个示例中Component 是一个接口定义了组件的通用行为。File 类代表叶子节点它实现了 Component 接口但不允许有子节点。Folder 类代表复合节点它可以包含其他 Component 对象即文件和文件夹。operation() 方法在 Folder 类中被重写以递归地处理所有子组件。
客户端代码通过创建文件夹和文件对象并将它们组织成树状结构来演示组合模式的使用。通过调用根文件夹的 operation() 方法可以递归地处理整个文件系统中的所有文件和文件夹。
9.装饰器模式(Decorator
装饰器模式Decorator Pattern是一种结构型设计模式它允许你通过添加一个或多个装饰器来动态地给一个对象添加一些额外的职责。就增加功能来说装饰器模式相比生成子类更为灵活。这种模式创建了一个包装对象也就是装饰器来包裹真实对象。
下面是一个使用Java实现的装饰器模式的简单示例。在这个例子中我们将创建一个简单的咖啡系统包括不同类型的咖啡和不同的调料如牛奶和摩卡。
首先定义一个咖啡Beverage接口所有的饮料都实现这个接口 public interface Beverage { String getDescription(); double cost(); } 然后实现一个具体的咖啡类如Espresso它实现了Beverage接口 public class Espresso implements Beverage { Override public String getDescription() { return Espresso; } Override public double cost() { return 1.99; } } 接下来定义一个装饰器抽象类它同样实现了Beverage接口并持有一个Beverage类型的对象引用 public abstract class BeverageDecorator implements Beverage { protected Beverage beverage; public BeverageDecorator(Beverage beverage) { this.beverage beverage; } Override public String getDescription() { return beverage.getDescription(); } Override public double cost() { return beverage.cost(); } } 现在实现具体的装饰器类比如Milk牛奶和Mocha摩卡 public class Milk extends BeverageDecorator { public Milk(Beverage beverage) { super(beverage); } Override public String getDescription() { return beverage.getDescription() , Milk; } Override public double cost() { return beverage.cost() 0.10; } } public class Mocha extends BeverageDecorator { public Mocha(Beverage beverage) { super(beverage); } Override public String getDescription() { return beverage.getDescription() , Mocha; } Override public double cost() { return beverage.cost() 0.20; } } 最后我们可以这样使用装饰器模式来创建并打印不同调料的咖啡 public class StarbuzzCoffee { public static void main(String[] args) { Beverage beverage new Espresso(); System.out.println(beverage.getDescription() $ beverage.cost()); Beverage beverage2 new Milk(new Espresso()); System.out.println(beverage2.getDescription() $ beverage2.cost()); Beverage beverage3 new Mocha(new Milk(new Espresso())); System.out.println(beverage3.getDescription() $ beverage3.cost()); // 可以继续添加更多的装饰器 } } 在这个例子中我们创建了Espresso对象并使用Milk和Mocha装饰器来动态地添加调料和价格。这种方式使得代码更加灵活和可扩展因为它允许我们在不修改现有类的情况下通过添加新的装饰器来添加新的功能。
10.外观模式(Facade)
外观模式为子系统中的一组接口提供一个统一的接口。外观模式定义了一个高层接口这个接口使得这一子系统更加容易使用。
假设我们有一个系统该系统用于处理文件的各种操作比如读取、写入和删除文件。这些操作分别由不同的类处理。为了简化对这些操作的调用我们可以使用外观模式来提供一个统一的接口。 // 文件读取类 class FileReader { public String read(String filename) { // 模拟读取文件内容 return 文件内容 filename; } } // 文件写入类 class FileWriter { public void write(String filename, String content) { // 模拟写入文件内容 System.out.println(向文件 filename 写入内容 content); } } // 文件删除类 class FileDeleter { public void delete(String filename) { // 模拟删除文件 System.out.println(删除文件 filename); } } 然后我们定义一个外观类来封装这些操作 // 文件操作外观类 class FileFacade { private FileReader reader; private FileWriter writer; private FileDeleter deleter; public FileFacade() { this.reader new FileReader(); this.writer new FileWriter(); this.deleter new FileDeleter(); } // 提供一个统一的接口 public void performFileOperations() { String filename example.txt; String content Hello, Facade Pattern!; // 读取文件 String fileContent reader.read(filename); System.out.println(fileContent); // 写入文件 writer.write(filename, content); // 删除文件这里仅为示例实际可能不需要立即删除 deleter.delete(filename); } } 最后我们创建一个测试类来使用外观类 public class FacadePatternDemo { public static void main(String[] args) { FileFacade facade new FileFacade(); facade.performFileOperations(); } } 在这个例子中FileFacade 类为复杂的文件操作提供了一个简单的接口。客户端在这个例子中是 FacadePatternDemo 类只需要与 FileFacade 交互而不需要直接与 FileReader、FileWriter 和 FileDeleter 交互这降低了系统的耦合度也简化了客户端的使用。
11.享元模式(Flyweight) 享元模式Flyweight Pattern主要用于减少创建对象的数量以减少内存占用和提高性能。它通过共享技术来支持大量细粒度的对象。在享元模式中对象的状态被分为内部状态intrinsic state和外部状态extrinsic state。内部状态是不变的可以在多个对象中共享而外部状态是随环境变化的不可以共享。
下面是一个Java代码示例演示了享元模式的应用。在这个例子中我们假设有一个简单的图形系统需要绘制大量的圆形但这些圆形可能只有少数几种颜色。为了节省内存我们可以使用享元模式来共享相同颜色的圆形对象。
首先定义圆形的接口和具体实现类享元类 // 圆形接口 interface Shape { void draw(String color); } // 圆形具体实现类享元类 class Circle implements Shape { private String color; // 内部状态通常设置为私有以封装对象 // 构造函数设置内部状态 public Circle(String color) { this.color color; } // 使用内部状态和外部状态绘制圆形 Override public void draw(String color) { System.out.println(Drawing Circle[ color : this.color ]); } // 获取圆形颜色用于演示 public String getColor() { return color; } } 注意上面的draw方法实际上接受了一个外部状态即传递给方法的color参数但在这个例子中我们主要关注内部状态即对象创建时设置的color。在实际应用中你可能需要设计接口和方法以便更好地分离内部状态和外部状态。
接下来定义享元工厂类用于管理共享对象 // 享元工厂类 class ShapeFactory { private static final HashMapString, Shape circleMap new HashMap(); // 获取圆形实例如果已存在则直接返回否则创建新的实例 public static Shape getCircle(String color) { Circle circle (Circle) circleMap.get(color); if (circle null) { circle new Circle(color); circleMap.put(color, circle); System.out.println(Creating Circle of color : color); } return circle; } } 最后客户端代码使用享元工厂来获取圆形实例并绘制它们 public class FlyweightPatternDemo { private static final String COLORS[] { Red, Green, Blue, White, Black }; public static void main(String[] args) { for (int i 0; i 20; i) { Circle circle (Circle) ShapeFactory.getCircle(getRandomColor()); circle.draw(getRandomColor()); // 注意这里传递的color是外部状态仅用于演示 } } // 简单的随机数生成器用于从预定义的颜色数组中获取颜色 private static String getRandomColor() { return COLORS[(int) (Math.random() * COLORS.length)]; } } 注意在这个例子中draw方法同时接收了内部状态和外部状态作为参数这实际上并不是享元模式的最佳实践。为了更清晰地展示享元模式你应该设计接口和方法使得内部状态如圆形的颜色在对象创建时确定并通过不同的方法或参数来影响外部状态如绘制时的位置、大小等。然而为了简化示例这里将两者都作为参数传递给了draw方法。
在实际应用中你应该根据具体需求来设计享元类、工厂类和客户端代码以确保内部状态被正确共享并且外部状态能够灵活地影响对象的行为。
12.代理模式(Proxy) 代理模式Proxy Pattern是一种结构型设计模式它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用并且可以通过代理对象来添加一些额外的功能如权限控制、日志记录、缓存等。
在Java中代理模式可以通过静态代理和动态代理两种方式实现。静态代理是在编译时就已经确定代理类的类而动态代理是在运行时动态地生成代理类。这里我将分别给出静态代理和动态代理使用JDK动态代理的示例。
静态代理示例
首先定义一个接口和该接口的实现类即目标对象 // 接口 interface Image { void display(); } // 目标对象 class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename filename; loadFromDisk(filename); } // 模拟从磁盘加载图片 private void loadFromDisk(String filename) { System.out.println(Loading filename); } Override public void display() { System.out.println(Displaying filename); } } // 代理类 class ProxyImage implements Image { private RealImage realImage; private String filename; public ProxyImage(String filename) { this.filename filename; } Override public void display() { if (realImage null) { realImage new RealImage(filename); } realImage.display(); } } 客户端代码 public class ProxyPatternDemo { public static void main(String[] args) { Image image new ProxyImage(test.jpg); // 图片将从硬盘加载但只在第一次调用display时 image.display(); // 输出Loading test.jpg 和 Displaying test.jpg // 再次调用display时图片已加载因此不会再次从硬盘加载 image.display(); // 仅输出Displaying test.jpg } } 动态代理示例使用JDK动态代理
首先需要实现一个InvocationHandler接口该接口定义了一个invoke方法用于在代理对象调用方法时被调用。 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 目标接口 interface Subject { void request(); } // 目标对象 class RealSubject implements Subject { Override public void request() { System.out.println(Handling request.); } } // 动态代理处理器 class DynamicProxyHandler implements InvocationHandler { private Object subject; public DynamicProxyHandler(Object subject) { this.subject subject; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(Before method: method.getName()); Object result method.invoke(subject, args); System.out.println(After method: method.getName()); return result; } } // 客户端代码 public class DynamicProxyPatternDemo { public static void main(String[] args) { Subject realSubject new RealSubject(); InvocationHandler handler new DynamicProxyHandler(realSubject); // 创建代理对象 Subject subject (Subject) Proxy.newProxyInstance( realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler ); // 调用代理对象的方法 subject.request(); } } 在这个动态代理示例中我们创建了一个RealSubject类作为目标对象它实现了Subject接口。然后我们定义了一个DynamicProxyHandler类它实现了InvocationHandler接口用于在代理对象调用方法时添加额外逻辑。最后我们使用Proxy.newProxyInstance方法动态地创建了一个Subject接口的代理对象并在客户端代码中通过该代理对象调用request方法。
13.策略模式(Strategy)
策略模式Strategy Pattern是一种行为型设计模式它定义了一系列的算法并将每一种算法封装起来使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。
在Java中策略模式通常通过定义一系列的算法类策略类这些类都实现一个共同的接口。然后客户端代码可以根据需要选择使用哪一个算法类。
下面是一个Java代码示例展示了策略模式的应用。在这个例子中我们将实现一个简单的排序算法选择包括快速排序和冒泡排序两种策略。
首先定义排序策略的接口 // 排序策略接口 public interface SortStrategy { void sort(int[] array); } 然后实现具体的排序算法策略类 // 快速排序策略 public class QuickSortStrategy implements SortStrategy { Override public void sort(int[] array) { // 这里只是简单模拟实际应实现快速排序算法 System.out.println(Using Quick Sort); // ... 实现快速排序算法 } } // 冒泡排序策略 public class BubbleSortStrategy implements SortStrategy { Override public void sort(int[] array) { // 这里只是简单模拟实际应实现冒泡排序算法 System.out.println(Using Bubble Sort); // ... 实现冒泡排序算法 } } 接下来定义一个上下文类Context它接受客户的请求然后委托给一个策略对象来执行具体的算法 // 排序上下文 public class SortContext { private SortStrategy strategy; public SortContext(SortStrategy strategy) { this.strategy strategy; } // 设置排序策略 public void setSortStrategy(SortStrategy strategy) { this.strategy strategy; } // 对数组进行排序 public void sortArray(int[] array) { strategy.sort(array); } } 最后客户端代码根据需要选择合适的排序策略 public class StrategyPatternDemo { public static void main(String[] args) { int[] numbers {5, 3, 8, 4, 2}; // 使用快速排序策略 SortContext context new SortContext(new QuickSortStrategy()); context.sortArray(numbers); // 假设后来决定使用冒泡排序策略 context.setSortStrategy(new BubbleSortStrategy()); context.sortArray(numbers); } } 注意上面的sort方法只是简单地打印出了使用的排序算法名称并没有真正实现排序算法。在实际应用中你应该在每个策略类中实现具体的排序算法。
策略模式的主要优点包括 算法可以自由切换。 避免使用多重条件判断。 扩展性良好。如果增加一个新的排序算法只需要增加一个实现了SortStrategy接口的策略类即可。
14.模板方法模式Template Method
模板方法模式Template Method Pattern是一种行为型设计模式它定义了一个操作中的算法的骨架而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
在Java中模板方法模式通常通过定义一个抽象类来实现这个抽象类中定义了一个或多个抽象方法即算法的某些步骤以及一个模板方法即算法的骨架。子类通过继承这个抽象类并实现其中的抽象方法来完成算法的具体步骤。
下面是一个Java代码示例展示了模板方法模式的应用。在这个例子中我们将实现一个简单的咖啡制作流程包括冲泡brew和添加调料addCondiments两个步骤。冲泡步骤是固定的但添加调料的步骤可以根据不同的咖啡类型而有所不同。
首先定义一个抽象类CaffeineBeverage其中包含模板方法prepareRecipe和抽象方法brew、addCondiments abstract class CaffeineBeverage { // 模板方法 final void prepareRecipe() { //烧水 boilWater(); //冲泡 brew(); //倒入杯子 pourInCup(); if (customerWantsCondiments()) { //添加调料 addCondiments(); } } // 各个步骤的具体实现除了brew和addCondiments void boilWater() { System.out.println(Boiling water); } abstract void brew(); void pourInCup() { System.out.println(Pouring into cup); } boolean customerWantsCondiments() { return true; } abstract void addCondiments(); } 然后创建具体类Espresso和HouseBlend来继承CaffeineBeverage并实现brew和addCondiments方法 class Espresso extends CaffeineBeverage { Override void brew() { System.out.println(在细粒咖啡中滴入浓缩咖啡); } Override void addCondiments() { System.out.println(添加浓缩咖啡调味品); } } class HouseBlend extends CaffeineBeverage { Override void brew() { System.out.println(浸泡自制混合咖啡); } Override void addCondiments() { System.out.println(添加自制混合调味品牛奶和糖); } Override boolean customerWantsCondiments() { // 假设顾客总是想要House Blend的调料 return true; } } 最后客户端代码可以通过创建Espresso或HouseBlend对象并调用其prepareRecipe方法来准备咖啡 public class TemplateMethodPatternDemo { public static void main(String[] args) { CaffeineBeverage espresso new Espresso(); System.out.println(Making an espresso:); espresso.prepareRecipe(); CaffeineBeverage houseBlend new HouseBlend(); System.out.println(\nMaking a house blend coffee:); houseBlend.prepareRecipe(); } } 输出将展示不同咖啡类型的制备过程其中冲泡和倒入杯中的步骤是固定的但添加调料的步骤会根据咖啡类型的不同而有所不同。
15.观察者模式(Observer)
观察者模式Observer Pattern是一种行为型设计模式它定义了一种一对多的依赖关系让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时会通知所有观察者对象使它们能够自动更新自己。
在Java中实现观察者模式通常涉及到定义主题Subject接口和观察者Observer接口然后创建具体的主题类和观察者类。不过从Java 1.0开始Java的java.util包中就提供了一个Observable类和Observer接口但自Java 9起Observable类已被标记为过时deprecated推荐使用其他方式实现观察者模式如使用Java的事件监听器机制或第三方库。
下面是一个简化的Java代码示例不依赖于java.util.Observable和java.util.Observer而是手动实现观察者模式
首先定义观察者接口 import java.util.ArrayList; import java.util.List; // 观察者接口 interface Observer { void update(String message); } // 具体的观察者类 class ConcreteObserver implements Observer { private String name; public ConcreteObserver(String name) { this.name name; } Override public void update(String message) { System.out.println(name received: message); } } 然后定义主题接口和具体的主题类 // 主题接口通常包含一个注册观察者和通知观察者的方法 interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(String message); } // 具体的主题类 class ConcreteSubject implements Subject { private ListObserver observers new ArrayList(); Override public void registerObserver(Observer o) { if (!observers.contains(o)) { observers.add(o); } } Override public void removeObserver(Observer o) { observers.remove(o); } Override public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } // 假设这是主题状态变化时调用的方法 public void someBusinessLogic() { // ... 执行一些业务逻辑 System.out.println(Business logic executed.); notifyObservers(State has changed!); } } 最后客户端代码 public class ObserverPatternDemo { public static void main(String[] args) { ConcreteSubject subject new ConcreteSubject(); Observer observer1 new ConcreteObserver(Observer 1); Observer observer2 new ConcreteObserver(Observer 2); Observer observer3 new ConcreteObserver(Observer 3); subject.registerObserver(observer1); subject.registerObserver(observer2); subject.registerObserver(observer3); // 改变主题状态并通知所有观察者 subject.someBusinessLogic(); // 移除一个观察者 subject.removeObserver(observer2); // 再次改变主题状态并通知所有观察者除了observer2 subject.someBusinessLogic(); } } 在这个例子中ConcreteSubject类充当了主题的角色它维护了一个观察者列表并在状态变化时通过调用notifyObservers方法来通知所有注册的观察者。ConcreteObserver类实现了Observer接口并在接收到通知时执行相应的操作。客户端代码通过创建主题和观察者对象并将它们连接起来展示了观察者模式的基本用法。
16.迭代器模式(Iterator)
迭代器模式Iterator Pattern是一种行为型设计模式它提供了一种方法顺序访问一个聚合对象如列表、集合中的各个元素而又不暴露该对象的内部表示。迭代器模式将遍历的职责从聚合对象转移到迭代器对象上从而使聚合对象与遍历算法分离。
在Java中迭代器模式已经被内置在java.util.Iterator接口和java.util.Collection接口的实现中如List、Set等。下面我将提供一个简单的自定义迭代器模式的示例以便更好地理解其工作原理。
首先定义一个聚合接口例如一个自定义的集合 interface MyCollection { Iterator createIterator(); } 接下来定义迭代器接口它包含遍历集合所需的方法 interface Iterator { boolean hasNext(); Object next(); } 然后实现一个具体的聚合类比如一个简单的数字列表 import java.util.ArrayList; import java.util.List; class NumberList implements MyCollection { private ListInteger numbers new ArrayList(); public void add(int number) { numbers.add(number); } Override public Iterator createIterator() { return new NumberListIterator(this); } // Getter 用于迭代器内部访问 public ListInteger getNumbers() { return numbers; } } 实现具体的迭代器类它持有对聚合对象的引用并遍历聚合对象中的元素 class NumberListIterator implements Iterator { private NumberList numberList; private int currentIndex 0; public NumberListIterator(NumberList numberList) { this.numberList numberList; } Override public boolean hasNext() { return currentIndex numberList.getNumbers().size(); } Override public Object next() { if (!hasNext()) { throw new NoSuchElementException(); } return numberList.getNumbers().get(currentIndex); } } 最后客户端代码使用迭代器遍历集合 public class IteratorPatternDemo { public static void main(String[] args) { NumberList numberList new NumberList(); numberList.add(1); numberList.add(2); numberList.add(3); Iterator iterator numberList.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } } 在这个例子中NumberList是聚合对象它维护了一个整数列表并提供了创建迭代器的方法。NumberListIterator是迭代器对象它实现了Iterator接口并能够遍历NumberList中的元素。客户端代码通过调用NumberList的createIterator方法来获取迭代器并使用迭代器遍历集合。
注意这个示例是为了说明迭代器模式的工作原理而简化的。在实际应用中Java集合框架已经提供了丰富的迭代器实现你不需要从头开始实现它们。
17.责任链模式(Chain of Responsibility)
责任链模式Chain of Responsibility Pattern是一种行为型设计模式它为请求的发送者和接收者之间解耦提供了一种松耦合的方式使得多个对象都有机会处理这个请求或者将这个请求传递给链中的下一个对象直到有一个对象处理它为止。
在Java中实现责任链模式通常需要定义一个抽象的处理者Handler类它包含一个指向下一个处理者的引用和一个处理请求的接口方法。具体的处理者类将继承这个抽象类并实现处理请求的方法。
下面是一个简单的Java代码示例展示了责任链模式的应用。在这个例子中我们将实现一个简单的日志处理系统其中日志消息可以根据其优先级如DEBUG、INFO、ERROR被不同的处理器处理。
首先定义日志级别和抽象的处理者接口 // 日志级别枚举 public enum LogLevel { DEBUG, INFO, ERROR } // 抽象处理者 abstract class Logger { protected int level; protected Logger nextLogger; public void setNextLogger(Logger nextLogger) { this.nextLogger nextLogger; } // 抽象方法用于处理日志 public void write(LogLevel level, String message) { if (this.level level.ordinal()) { writeMessage(message); } if (nextLogger ! null) { nextLogger.write(level, message); } } // 具体写日志的方法由子类实现 protected abstract void writeMessage(String message); } 然后定义具体的处理者类 // 具体处理者ConsoleLogger只记录ERROR级别的日志 class ConsoleLogger extends Logger { public ConsoleLogger(int level) { this.level level; } Override protected void writeMessage(String message) { System.out.println(Console: message); } } // 具体处理者FileLogger记录ERROR和INFO级别的日志 class FileLogger extends Logger { private String fileName; public FileLogger(int level, String fileName) { this.level level; this.fileName fileName; } Override protected void writeMessage(String message) { // 假设有一个方法可以将日志写入文件 System.out.println(File: fileName - message); } } // 具体处理者ErrorLogger只记录ERROR级别的日志到特定文件 class ErrorLogger extends Logger { private String errorFileName; public ErrorLogger(int level, String errorFileName) { this.level level; this.errorFileName errorFileName; } Override protected void writeMessage(String message) { // 假设有一个方法可以将错误日志写入特定文件 System.out.println(ErrorFile: errorFileName - message); } } 最后客户端代码使用这些处理者构建责任链并发送日志消息 public class ChainPatternDemo { private static Logger getChainOfLoggers() { // 创建链中的各个日志记录器 Logger errorLogger new ErrorLogger(LogLevel.ERROR.ordinal(), errors.log); Logger fileLogger new FileLogger(LogLevel.INFO.ordinal(), logs.log); Logger consoleLogger new ConsoleLogger(LogLevel.DEBUG.ordinal()); // 设置链的顺序 errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } public static void main(String[] args) { Logger loggerChain getChainOfLoggers(); loggerChain.write(LogLevel.ERROR, This is an error message.); loggerChain.write(LogLevel.INFO, This is an information.); loggerChain.write(LogLevel.DEBUG, This is a debug level information.); } } 在这个例子中我们创建了一个日志处理的责任链其中ErrorLogger只处理ERROR级别的日志FileLogger处理ERROR和INFO级别的日志而ConsoleLogger则处理所有级别的日志。通过调用write方法并传递日志级别和消息我们可以将消息沿着链传递直到它被适当的处理者处理。
18.命令模式(Command)
在命令模式中我们有一个Command接口它定义了执行操作的接口。然后具体命令类实现了这个接口并关联到一个接收者Receiver对象上调用接收者相应的操作。调用者Invoker通过命令对象来执行操作而不需要直接调用接收者的操作。 // Command接口 interface Command { void execute(); } // 接收者 class Receiver { public void action() { System.out.println(Action performed by Receiver); } } // 具体命令类 class ConcreteCommand implements Command { private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver receiver; } Override public void execute() { receiver.action(); } } // 调用者 class Invoker { private Command command; public Invoker(Command command) { this.command command; } public void setCommand(Command command) { this.command command; } public void executeCommand() { command.execute(); } } // 客户端代码 public class Client { public static void main(String[] args) { Receiver receiver new Receiver(); Command command new ConcreteCommand(receiver); Invoker invoker new Invoker(command); invoker.executeCommand(); // 输出: Action performed by Receiver // 可以在不修改Invoker类的前提下更换命令 Command anotherCommand new AnotherConcreteCommand(); // 假设AnotherConcreteCommand是另一个实现了Command的类 invoker.setCommand(anotherCommand); invoker.executeCommand(); // 执行AnotherConcreteCommand的execute方法 } } // 假设的AnotherConcreteCommand类 class AnotherConcreteCommand implements Command { Override public void execute() { System.out.println(Executing another action); } } 请注意由于问题中并未要求实现AnotherConcreteCommand我为了展示命令模式中的灵活性而假设了其存在。在实际应用中你可以根据需要创建多个具体命令类。
这个示例展示了命令模式的核心思想将请求封装为对象从而使你可用不同的请求、队列、日志来参数化其他对象。命令模式也支持可撤销的操作。
19.备忘录模式(Memento)
在Java中备忘录模式Memento Pattern是一种行为设计模式它允许在不暴露对象内部状态的情况下捕获并保存一个对象的内部状态以便在将来某个时刻可以恢复到这个状态。备忘录模式通常涉及三个角色发起人Originator、备忘录Memento和负责人Caretaker。 // 备忘录接口 interface Memento { // 这里可以根据需要添加方法来访问备忘录中的状态 } // 具体备忘录类保存发起人的状态 class OriginatorState implements Memento { // 假设发起人有一个状态是字符串 private String state; public OriginatorState(String state) { this.state state; } // 可能需要的方法来恢复状态虽然在这个简单的示例中未直接使用 public String getState() { return state; } } // 发起人类 class Originator { private String state; // 创建一个备忘录保存当前状态 public Memento createMemento() { return new OriginatorState(state); } // 从备忘录恢复状态 public void restoreMemento(Memento memento) { OriginatorState os (OriginatorState) memento; this.state os.getState(); } // 更改状态的方法 public void setState(String state) { this.state state; } // 获取当前状态的方法为了演示 public String getState() { return state; } } // 负责人负责保存和恢复备忘录 class Caretaker { private Memento memento; // 设置备忘录 public void setMemento(Memento memento) { this.memento memento; } // 获取备忘录 public Memento getMemento() { return memento; } } // 客户端代码 public class Client { public static void main(String[] args) { Originator originator new Originator(); Caretaker caretaker new Caretaker(); originator.setState(State #1); caretaker.setMemento(originator.createMemento()); originator.setState(State #2); System.out.println(Current State: originator.getState()); // 输出: State #2 // 从备忘录恢复状态 originator.restoreMemento(caretaker.getMemento()); System.out.println(Restored State: originator.getState()); // 输出: State #1 } } 在这个示例中Originator 类有一个状态在这个例子中是一个字符串它可以通过 createMemento 方法来创建一个包含当前状态的备忘录对象。这个备忘录对象是一个 OriginatorState 类的实例它实现了 Memento 接口。Caretaker 类负责保存备忘录对象并提供方法来获取和设置备忘录。在客户端代码中我们演示了如何保存一个状态更改状态然后从保存的备忘录中恢复状态。
注意这个示例中的备忘录模式是非常基本的实际应用中可能需要更复杂的状态管理逻辑。