Java 设计模式通常分为 3 大类,分别是创建型模式、结构型模式和行为型模式。
创建型模式(Creational Patterns): 这些模式关注如何创建对象,包括单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式等。它们提供了一种灵活的方法来创建对象,同时隐藏了对象的创建逻辑,使得代码更容易维护和扩展。
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。
- 工厂模式(Factory Pattern):定义一个创建对象的接口,但由子类决定具体实例化哪个类。
- 抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
- 建造者模式(Builder Pattern):将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
- 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,而不是从头开始。
结构型模式(Structural Patterns): 这些模式关注如何组合类和对象以形成更大的结构,包括适配器模式、桥接模式、装饰器模式、组合模式、外观模式、享元模式和代理模式等。结构型模式可以帮助系统更好地设计对象之间的关系,使得系统更加灵活和可维护。
- 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。
- 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们可以独立变化。
- 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,而不影响其原始类。
- 组合模式(Composite Pattern):将对象组合成树形结构以表示"部分-整体"的层次结构。
- 外观模式(Facade Pattern):提供一个统一的接口,用于访问子系统中的一群接口。
- 享元模式(Flyweight Pattern):共享对象以减少内存使用和提高性能。
- 代理模式(Proxy Pattern):为其他对象提供一个代理,控制对这个对象的访问。
行为型模式(Behavioral Patterns): 这些模式关注对象之间的通信以及职责的分配,包括策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式和中介者模式等。行为型模式可以帮助系统更好地实现对象之间的交互,使得系统更加灵活和易于扩展。
- 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以相互替换。
- 模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟到子类中实现。
- 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,使得当一个对象状态发生变化时,所有依赖它的对象都得到通知并自动更新。
- 迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露其内部表示。
- 责任链模式(Chain of Responsibility Pattern):将请求的发送者和接收者解耦,将多个对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止。
- 命令模式(Command Pattern):将请求封装成一个对象,从而使用户可以用不同的请求参数来进行参数化。
- 备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。
- 状态模式(State Pattern):允许对象在其内部状态改变时改变它的行为。
- 访问者模式(Visitor Pattern):在不改变被访问者的前提下,定义新的操作方式。
- 中介者模式(Mediator Pattern):用一个中介对象来封装一系列对象交互,使各个对象不需要显式地相互引用,从而降低耦合度。
创建型模式(Creational Patterns)
单例模式
懒汉式单例:在首次使用时创建实例。
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
双重检查锁单例:在懒汉式的基础上增加双重检查,提高效率。
java
public class DoubleCheckedSingleton {
private static volatile DoubleCheckedSingleton instance;
private DoubleCheckedSingleton() {}
public static DoubleCheckedSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedSingleton();
}
}
}
return instance;
}
}
饿汉式单例:在类加载时就创建实例,线程安全但可能浪费内存。
java
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
静态内部类单例 :通过静态内部类实现延迟加载和线程安全。
静态内部类实现单例模式具有延迟加载和线程安全的特性,这是因为Java类加载器机制和类加载的线程安全性保证了这种实现方式的有效性。
- 延迟加载:
静态内部类在Java中是在首次被使用时才会被加载,而不是在外部类加载时就被加载。因此,只有当调用 getInstance() 方法时,静态内部类才会被加载并创建单例对象。
这种延迟加载的特性可以节省内存和系统资源,在应用程序中只有在需要时才会实际创建单例对象,而不是在程序启动时就创建。 - 线程安全:
静态内部类在Java中是一个独立的类,它的加载过程由Java类加载器保证线程安全。因此,当多个线程同时调用 getInstance() 方法时,不会出现竞态条件或者多次创建实例的情况。
这是因为Java类加载器在加载类的过程中会对类进行初始化,保证了类加载的原子性和线程安全性。
java
public class StaticInnerSingleton {
private StaticInnerSingleton() {}
private static class SingletonHolder {
private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
简单工厂模式
java
// 抽象产品:图形接口
interface Shape {
void draw();
}
// 具体产品:圆形
class Circle implements Shape {
@Override
public void draw() {
System.out.println("画一个圆形");
}
}
// 具体产品:正方形
class Square implements Shape {
@Override
public void draw() {
System.out.println("画一个正方形");
}
}
// 具体产品:矩形
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
}
// 简单工厂:图形工厂
class ShapeFactory {
public Shape createShape(String type) {
if (type.equalsIgnoreCase("circle")) {
return new Circle();
} else if (type.equalsIgnoreCase("square")) {
return new Square();
} else if (type.equalsIgnoreCase("rectangle")) {
return new Rectangle();
} else {
throw new IllegalArgumentException("无效的图形类型");
}
}
}
public class FactoryPatternExample {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
Shape circle = factory.createShape("circle");
circle.draw();
Shape square = factory.createShape("square");
square.draw();
Shape rectangle = factory.createShape("rectangle");
rectangle.draw();
}
}
工厂方法模式
java
// 抽象产品:图形接口
interface Shape {
void draw();
}
// 具体产品:圆形
class Circle implements Shape {
@Override
public void draw() {
System.out.println("画一个圆形");
}
}
// 具体产品:正方形
class Square implements Shape {
@Override
public void draw() {
System.out.println("画一个正方形");
}
}
// 具体产品:矩形
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
}
// 抽象工厂:图形工厂接口
interface ShapeFactory {
Shape createShape();
}
// 具体工厂:圆形工厂
class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle();
}
}
// 具体工厂:正方形工厂
class SquareFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Square();
}
}
// 具体工厂:矩形工厂
class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
}
public class FactoryMethodPatternExample {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw();
ShapeFactory squareFactory = new SquareFactory();
Shape square = squareFactory.createShape();
square.draw();
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw();
}
}
抽象工厂模式
java
// 抽象产品 A:按钮接口
interface Button {
void display();
}
// 具体产品 A1:Windows 按钮
class WindowsButton implements Button {
@Override
public void display() {
System.out.println("显示 Windows 风格按钮");
}
}
// 具体产品 A2:Mac 按钮
class MacButton implements Button {
@Override
public void display() {
System.out.println("显示 Mac 风格按钮");
}
}
// 抽象产品 B:文本框接口
interface TextBox {
void display();
}
// 具体产品 B1:Windows 文本框
class WindowsTextBox implements TextBox {
@Override
public void display() {
System.out.println("显示 Windows 风格文本框");
}
}
// 具体产品 B2:Mac 文本框
class MacTextBox implements TextBox {
@Override
public void display() {
System.out.println("显示 Mac 风格文本框");
}
}
// 抽象工厂:界面风格工厂接口
interface GUIFactory {
Button createButton(); // 创建按钮
TextBox createTextBox(); // 创建文本框
}
// 具体工厂 A:Windows 风格工厂
class WindowsGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
// 具体工厂 B:Mac 风格工厂
class MacGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
}
public class AbstractFactoryPatternExample {
public static void main(String[] args) {
// 创建 Windows 风格的界面
GUIFactory windowsFactory = new WindowsGUIFactory();
Button windowsButton = windowsFactory.createButton();
TextBox windowsTextBox = windowsFactory.createTextBox();
windowsButton.display();
windowsTextBox.display();
// 创建 Mac 风格的界面
GUIFactory macFactory = new MacGUIFactory();
Button macButton = macFactory.createButton();
TextBox macTextBox = macFactory.createTextBox();
macButton.display();
macTextBox.display();
}
}
工厂方法模式和抽象工厂有什么区别
举例来说,假设我们有一个游戏中的角色装备系统:
- 如果只关心创建不同种类的武器(比如剑、枪、弓等),可以使用工厂方法模式。每个具体工厂类负责创建一种武器,比如剑工厂、枪工厂、弓工厂。
- 如果需要创建一整套角色装备(比如武器、防具、饰品等),可以使用抽象工厂模式。每个具体工厂类负责创建一个角色装备套装,比如剑士套装工厂、枪手套装工厂、弓箭手套装工厂。
总体来说,工厂方法模式适用于单个产品族的创建,而抽象工厂模式适用于多个产品族的创建。选择哪种模式取决于具体的需求,包括产品的复杂性、产品族的关系等因素。
建造者模式
建造者模式
(Builder Pattern)是一种创建型设计模式,它主要用于构建一个复杂对象,将对象的构建过程与表示分离,从而使得同样的构建过程可以创建不同的表示。建造者模式的核心思想是将一个复杂对象的构建过程分解为多个简单对象的构建步骤,并将这些构建步骤封装在一个指导者(Director)类中,通过指导者类按照一定的顺序组装这些简单对象,最终构建出复杂对象。
建造者模式包含以下几个角色:
- 产品(Product): 定义了需要构建的复杂对象的接口。
- 抽象建造者(Builder): 定义了构建复杂对象的方法,包括构建各个部件的方法。
- 具体建造者(Concrete Builder): 实现了抽象建造者接口,负责具体的构建工作,构建过程中创建复杂对象的各个部件。
- 指导者(Director): 负责按照一定的顺序调用具体建造者的方法,组装复杂对象。
java
// 产品:报告
class Report {
private String title;
private String content;
public Report(String title, String content) {
this.title = title;
this.content = content;
}
@Override
public String toString() {
return "Report{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
// 抽象建造者:报告建造者接口
interface ReportBuilder {
void buildTitle();
void buildContent();
Report getResult();
}
// 具体建造者:普通报告建造者
class NormalReportBuilder implements ReportBuilder {
private Report report;
public NormalReportBuilder() {
report = new Report("", "");
}
@Override
public void buildTitle() {
report.title = "普通报告标题";
}
@Override
public void buildContent() {
report.content = "普通报告内容";
}
@Override
public Report getResult() {
return report;
}
}
// 具体建造者:精简报告建造者
class SimpleReportBuilder implements ReportBuilder {
private Report report;
public SimpleReportBuilder() {
report = new Report("", "");
}
@Override
public void buildTitle() {
report.title = "精简报告标题";
}
@Override
public void buildContent() {
report.content = "精简报告内容";
}
@Override
public Report getResult() {
return report;
}
}
// 指导者:报告指导者
class ReportDirector {
private ReportBuilder reportBuilder;
public ReportDirector(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
public Report constructReport() {
reportBuilder.buildTitle();
reportBuilder.buildContent();
return reportBuilder.getResult();
}
}
public class BuilderPatternReportExample {
public static void main(String[] args) {
ReportBuilder normalBuilder = new NormalReportBuilder();
ReportDirector normalDirector = new ReportDirector(normalBuilder);
Report normalReport = normalDirector.constructReport();
System.out.println("普通报告: " + normalReport);
ReportBuilder simpleBuilder = new SimpleReportBuilder();
ReportDirector simpleDirector = new ReportDirector(simpleBuilder);
Report simpleReport = simpleDirector.constructReport();
System.out.println("精简报告: " + simpleReport);
}
}
原型模式
(可忽略不看,还没有深入理解以及真实使用场景体验)
主要用于创建对象的克隆副本,而不是通过传统的构造函数来创建新的对象实例。原型模式通过复制现有对象的数据来创建新的对象,可以减少对象的创建成本和提高性能,特别适用于创建成本较高的对象或需要频繁创建相似对象的情况。
原型模式的核心思想是通过原型实例来指定要创建对象的种类,并且通过拷贝这个原型来创建新的对象。在 Java 中,原型模式通常通过实现 Cloneable 接口和重写 clone() 方法来实现对象的复制。
下面是一个简单的原型模式示例,假设我们有一个图形对象,包括矩形和圆形,我们可以使用原型模式来创建这些图形对象的克隆副本:
java
// 抽象原型:图形接口
interface Shape extends Cloneable {
void draw();
Shape clone();
}
// 具体原型:矩形
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
@Override
public Shape clone() {
try {
return (Shape) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
// 具体原型:圆形
class Circle implements Shape {
@Override
public void draw() {
System.out.println("画一个圆形");
}
@Override
public Shape clone() {
try {
return (Shape) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
public class PrototypePatternExample {
public static void main(String[] args) {
// 创建原型实例
Shape rectanglePrototype = new Rectangle();
Shape circlePrototype = new Circle();
// 使用原型创建新对象
Shape clonedRectangle = rectanglePrototype.clone();
Shape clonedCircle = circlePrototype.clone();
// 测试克隆对象
clonedRectangle.draw();
clonedCircle.draw();
}
}
结构型模式(Structural Patterns)
适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端期望的另一个接口。适配器模式主要用于解决接口不兼容的问题,使得原本因接口不匹配而无法一起工作的类可以协同工作。
适配器模式包含以下几个角色:
- 目标接口(Target): 定义客户端使用的接口,也就是客户端期望的接口。
- 适配者类(Adaptee): 需要被适配的类,它提供了不兼容的接口。
- 适配器(Adapter): 实现了目标接口,并持有一个适配者对象,在适配器中将客户端调用转换为适配者类的接口调用。
下面是一个简单的适配器模式示例,假设有一个英国插头需要在中国使用,但英国插头和中国插座不兼容,我们可以使用适配器模式来解决这个问题:
java
// 目标接口:中国插座接口
interface ChineseSocket {
void insertChinesePlug();
}
// 适配者类:英国插头
class BritishPlug {
public void insertBritishPlug() {
System.out.println("插入英国插头");
}
}
// 适配器:英国插头适配器,实现中国插座接口
class BritishPlugAdapter implements ChineseSocket {
private BritishPlug britishPlug;
public BritishPlugAdapter(BritishPlug britishPlug) {
this.britishPlug = britishPlug;
}
@Override
public void insertChinesePlug() {
// 在适配器中调用英国插头的方法来实现中国插座接口
britishPlug.insertBritishPlug();
System.out.println("适配器转换:英国插头转换为中国插头");
}
}
// 客户端代码
public class AdapterPatternExample {
public static void main(String[] args) {
// 创建英国插头和适配器
BritishPlug britishPlug = new BritishPlug();
BritishPlugAdapter adapter = new BritishPlugAdapter(britishPlug);
// 使用适配器插入中国插座
adapter.insertChinesePlug();
}
}
桥接模式
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化而不相互影响。桥接模式通过组合的方式将抽象部分和实现部分连接起来,而不是通过继承的方式,从而提高了系统的灵活性和可扩展性。
使用场景:
- 当一个类有多个维度的变化,并且这些变化需要独立地扩展时,可以使用桥接模式。例如,一个形状类有不同的颜色,而且形状和颜色的变化不相关,这时可以使用桥接模式将形状和颜色分离开来。
- 当希望一个抽象和它的实现部分可以独立扩展时,桥接模式也很有用。这样可以避免类爆炸式增长,每个抽象类只需关注自己的变化。
java
// 定义颜色接口
interface Color {
void applyColor();
}
// 实现颜色接口的具体类
class RedColor implements Color {
@Override
public void applyColor() {
System.out.println("Applying red color");
}
}
class BlueColor 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;
}
abstract void applyColor();
}
// 具体形状类
class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
void applyColor() {
System.out.print("Square with ");
color.applyColor();
}
}
class Circle extends Shape {
public Circle(Color color) {
super(color);
}
@Override
void applyColor() {
System.out.print("Circle with ");
color.applyColor();
}
}
// 使用桥接模式
public class BridgePatternExample {
public static void main(String[] args) {
Color red = new RedColor();
Color blue = new BlueColor();
Shape redSquare = new Square(red);
Shape blueCircle = new Circle(blue);
redSquare.applyColor();
blueCircle.applyColor();
}
}
装饰器模式
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向现有对象动态地添加新功能,同时不改变其结构。装饰器模式通过创建一个包装对象来实现对原始对象的包装,从而使得可以在运行时动态地添加新的行为或功能。
装饰器模式的主要目的是避免类的多层继承导致类的数量急剧增加和类之间关系复杂的问题,通过组合的方式实现对对象的功能扩展,使得系统更加灵活、易于维护和扩展。
在装饰器模式中,通常包含以下几个角色:
- 抽象构件(Component): 定义了被装饰对象的接口,可以是抽象类或接口。
- 具体构件(ConcreteComponent): 实现了抽象构件接口,是被装饰的具体对象。
- 装饰器(Decorator): 持有一个抽象构件对象,并实现了抽象构件接口,通常是一个抽象类,用于包装具体构件对象并动态添加新的功能。
- 具体装饰器(ConcreteDecorator): 继承自装饰器类,实现了具体的装饰逻辑,可以根据需要扩展或修改被装饰对象的行为。
使用场景:
- 当需要动态地给对象添加新的功能或行为,且不希望通过类的继承来实现时,可以使用装饰器模式。
- 当系统中存在大量的相似但不同组合的对象时,可以使用装饰器模式来避免类的爆炸性增长。
java
// 抽象构件:咖啡接口
interface Coffee {
String getDescription();
double cost();
}
// 具体构件:黑咖啡
class BlackCoffee implements Coffee {
@Override
public String getDescription() {
return "黑咖啡";
}
@Override
public double cost() {
return 10.0;
}
}
// 装饰器:调料装饰器
abstract class CondimentDecorator implements Coffee {
protected Coffee coffee;
public CondimentDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double cost() {
return coffee.cost();
}
}
// 具体装饰器:牛奶调料
class MilkDecorator extends CondimentDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 牛奶";
}
@Override
public double cost() {
return coffee.cost() + 2.0;
}
}
// 具体装饰器:糖调料
class SugarDecorator extends CondimentDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 糖";
}
@Override
public double cost() {
return coffee.cost() + 1.0;
}
}
// 客户端代码
public class DecoratorPatternExample {
public static void main(String[] args) {
// 创建黑咖啡对象
Coffee blackCoffee = new BlackCoffee();
// 添加牛奶调料
Coffee milkCoffee = new MilkDecorator(blackCoffee);
// 添加糖调料
Coffee sweetMilkCoffee = new SugarDecorator(milkCoffee);
// 输出描述和价格
System.out.println(sweetMilkCoffee.getDescription());
System.out.println("价格:" + sweetMilkCoffee.cost());
}
}
组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它允许将对象组合成树形结构来表示"整体-部分"的层次结构。组合模式使得客户端可以统一处理单个对象和组合对象,无需区分它们的具体类型,从而简化了客户端的代码。
使用场景:
- 当需要表示对象的层次结构,并且希望客户端能够统一处理单个对象和组合对象时,可以使用组合模式。例如,文件系统中的文件夹和文件就可以用组合模式来表示,客户端可以对文件夹和文件进行统一的操作。
- 当希望客户端忽略对象与组合对象之间的差异,统一对待它们时,组合模式也很有用。这样可以减少客户端的复杂性。
代码示例:
假设我们有一个组织结构,包括部门和员工,可以使用组合模式来表示:
java
import java.util.ArrayList;
import java.util.List;
// 抽象组件类
interface Component {
void display();
}
// 叶子组件类(员工)
class Employee implements Component {
private String name;
public Employee(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("Employee: " + name);
}
}
// 复合组件类(部门)
class Department implements Component {
private String name;
private List<Component> children = new ArrayList<>();
public Department(String name) {
this.name = name;
}
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void display() {
System.out.println("Department: " + name);
for (Component component : children) {
component.display();
}
}
}
// 使用组合模式
public class CompositePatternExample {
public static void main(String[] args) {
// 创建部门和员工
Department engineering = new Department("Engineering");
engineering.add(new Employee("John"));
engineering.add(new Employee("Jane"));
Department marketing = new Department("Marketing");
marketing.add(new Employee("Mike"));
marketing.add(new Employee("Emily"));
// 创建公司
Department company = new Department("Company");
company.add(engineering);
company.add(marketing);
// 显示公司组织结构
company.display();
}
}
外观模式
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一组接口,简化了客户端与子系统之间的交互。外观模式隐藏了系统的复杂性,提供了一个简单的接口供客户端使用。
使用场景:
- 当系统中存在复杂的子系统,客户端需要经常与这些子系统进行交互时,可以使用外观模式来简化客户端的操作。
- 当希望将系统的复杂性封装起来,提供一个更简洁的接口给客户端使用时,外观模式也很有用。
代码示例:
假设我们有一个音响系统,包括音响、CD播放器和灯光,可以使用外观模式来简化客户端操作:
java
// 子系统类:音响
class StereoSystem {
public void turnOn() {
System.out.println("Stereo system is on");
}
public void turnOff() {
System.out.println("Stereo system is off");
}
public void playMusic() {
System.out.println("Playing music on stereo system");
}
}
// 子系统类:CD播放器
class CdPlayer {
public void insertCd() {
System.out.println("CD inserted");
}
public void ejectCd() {
System.out.println("CD ejected");
}
public void play() {
System.out.println("Playing CD");
}
}
// 子系统类:灯光
class Light {
public void turnOn() {
System.out.println("Light is on");
}
public void turnOff() {
System.out.println("Light is off");
}
}
// 外观类:音响系统外观
class HomeTheaterFacade {
private StereoSystem stereo;
private CdPlayer cdPlayer;
private Light light;
public HomeTheaterFacade() {
stereo = new StereoSystem();
cdPlayer = new CdPlayer();
light = new Light();
}
public void watchMovie() {
light.turnOn();
stereo.turnOn();
cdPlayer.insertCd();
cdPlayer.play();
}
public void endMovie() {
cdPlayer.ejectCd();
stereo.turnOff();
light.turnOff();
}
}
// 使用外观模式
public class FacadePatternExample {
public static void main(String[] args) {
HomeTheaterFacade homeTheater = new HomeTheaterFacade();
// 开始观影
homeTheater.watchMovie();
// 结束观影
homeTheater.endMovie();
}
}
享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,它旨在通过共享对象来减少内存使用和提高性能。享元模式适用于存在大量相似对象的情况,通过共享这些相似对象的状态来减少内存消耗。
使用场景:
当系统中存在大量相似对象,并且这些对象可以共享部分状态时,可以使用享元模式。
当需要缓存对象以提高系统性能时,享元模式也很有用。通过共享对象,可以减少对象的创建和销毁,提高系统的响应速度。
java
import java.util.HashMap;
import java.util.Map;
// 抽象享元类:咖啡
interface Coffee {
void serveCoffee();
}
// 具体享元类:具体口味的咖啡
class Espresso implements Coffee {
private String name;
private double price;
public Espresso() {
this.name = "Espresso";
this.price = 2.5; // 假设价格为2.5美元
}
@Override
public void serveCoffee() {
System.out.println("Serving " + name + ", Price: $" + price);
}
}
class Latte implements Coffee {
private String name;
private double price;
public Latte() {
this.name = "Latte";
this.price = 3.0; // 假设价格为3.0美元
}
@Override
public void serveCoffee() {
System.out.println("Serving " + name + ", Price: $" + price);
}
}
// 享元工厂类:咖啡工厂
class CoffeeFactory {
private static Map<String, Coffee> coffeeMap = new HashMap<>();
public static Coffee getCoffee(String type) {
Coffee coffee = coffeeMap.get(type);
if (coffee == null) {
switch (type) {
case "Espresso":
coffee = new Espresso();
break;
case "Latte":
coffee = new Latte();
break;
default:
throw new IllegalArgumentException("Unknown coffee type: " + type);
}
coffeeMap.put(type, coffee);
}
return coffee;
}
}
// 客户端代码
public class CoffeeExample {
public static void main(String[] args) {
Coffee espresso1 = CoffeeFactory.getCoffee("Espresso");
espresso1.serveCoffee();
Coffee espresso2 = CoffeeFactory.getCoffee("Espresso");
espresso2.serveCoffee(); // 使用相同类型的咖啡对象,共享状态
Coffee latte = CoffeeFactory.getCoffee("Latte");
latte.serveCoffee();
}
}
代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象来控制对真实对象的访问。代理模式主要用于在访问对象时增加一层间接性,可以在不改变原始对象的情况下,对其进行一些额外的控制和管理。
代理模式的核心思想是通过引入一个代理对象来间接访问真实对象,代理对象可以在访问真实对象前后进行一些操作,例如权限控制、延迟加载、缓存等。
代理模式通常包含以下几个角色:
- 抽象主题(Subject): 定义了真实对象和代理对象的公共接口,可以是抽象类或接口。
- 真实主题(RealSubject): 实现了抽象主题接口,是真正的业务逻辑对象。
- 代理(Proxy): 持有对真实主题的引用,并实现了抽象主题接口,在其内部完成对真实主题的访问控制和其他操作。
代理模式可以分为静态代理
和动态代理
两种形式:
- 静态代理是在编译时已经确定了代理对象和真实对象的关系,代理类在编译时就确定了,不具有灵活性。
- 动态代理是在运行时动态生成代理对象,无需事先知道代理对象和真实对象的关系,具有更高的灵活性和扩展性。
使用场景:
- 对象访问需要控制或管理,例如权限控制、日志记录等。
- 对象创建或销毁需要延迟加载或懒加载。
- 对象的访问需要增加额外的操作,例如缓存、统计、校验等。
静态代理
java
// 抽象主题:图片接口
interface Image {
void display();
}
// 真实主题:图片加载器
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("加载图片:" + filename);
}
@Override
public void display() {
System.out.println("显示图片:" + filename);
}
}
// 代理:图片加载代理
class ImageProxy implements Image {
private RealImage realImage;
private String filename;
public ImageProxy(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
// do something
realImage.display();
// do something
}
}
// 客户端代码
public class ProxyPatternExample {
public static void main(String[] args) {
// 创建图片代理对象
Image proxyImage = new ImageProxy("test.jpg");
// 第一次显示图片,会加载图片
proxyImage.display();
System.out.println("-----");
// 第二次显示图片,不会再次加载图片
proxyImage.display();
}
}
动态代理
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主题:图片接口
interface Image {
void display();
}
// 真实主题:图片加载器
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("加载图片:" + filename);
}
@Override
public void display() {
System.out.println("显示图片:" + filename);
}
}
// 动态代理处理器:实现 InvocationHandler 接口
class ImageProxyHandler implements InvocationHandler {
private Object realImage;
public ImageProxyHandler(Object realImage) {
this.realImage = realImage;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// do something
Object result = method.invoke(realImage, args);
// do something
return result;
}
}
// 客户端代码
public class DynamicProxyPatternExample {
public static void main(String[] args) {
// 创建真实主题对象
Image realImage = new RealImage("test.jpg");
// 创建动态代理处理器
InvocationHandler handler = new ImageProxyHandler(realImage);
// 使用动态代理创建代理对象
Image proxyImage = (Image) Proxy.newProxyInstance(
realImage.getClass().getClassLoader(),
realImage.getClass().getInterfaces(),
handler);
// 使用代理对象显示图片
proxyImage.display();
}
}
行为型模式(Behavioral Patterns)
策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装成单独的类,使得它们可以互相替换。策略模式可以让算法的变化独立于使用算法的客户端。
使用场景:
- 当一个系统中有多个算法或行为,需要动态地在这些算法或行为之间切换时,可以使用策略模式。例如,一个电商系统中的支付方式可以有多种,用户可以选择不同的支付方式来支付订单。
- 当希望避免使用大量的条件语句来实现不同的算法逻辑时,策略模式也很有用。通过将每个算法封装成独立的策略类,可以提高代码的可维护性和可读性。
java
// 策略接口:支付策略
interface PaymentStrategy {
void pay(double amount);
}
// 具体策略类:支付宝支付
class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paying " + amount + " via Alipay");
}
}
// 具体策略类:微信支付
class WeChatPayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paying " + amount + " via WeChat Pay");
}
}
// 具体策略类:银联支付
class UnionPayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paying " + amount + " via UnionPay");
}
}
// 上下文类:支付上下文
class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void performPayment(double amount) {
strategy.pay(amount);
}
}
// 客户端代码
public class StrategyPatternExample {
public static void main(String[] args) {
PaymentStrategy alipay = new AlipayStrategy();
PaymentContext context = new PaymentContext(alipay);
context.performPayment(100.0);
PaymentStrategy wechatPay = new WeChatPayStrategy();
context = new PaymentContext(wechatPay);
context.performPayment(50.0);
PaymentStrategy unionPay = new UnionPayStrategy();
context = new PaymentContext(unionPay);
context.performPayment(80.0);
}
}
模板方法模式
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架,将具体步骤延迟到子类中实现。模板方法模式通过把不变的行为封装在父类中,而将可变的行为留给子类来实现,从而实现了代码的复用和扩展。
模板方法模式主要由以下几个角色组成:
- 抽象模板类(Abstract Template): 定义了一个模板方法,该方法中包含了算法的骨架和固定步骤,通常是一个抽象类。
- 具体模板类(Concrete Template): 继承自抽象模板类,实现了模板方法中的具体步骤,可以有多个具体模板类。
- 钩子方法(Hook Method): 在抽象模板类中定义的可选步骤,子类可以选择是否实现,用于在算法中添加额外的扩展点。
使用场景:
- 当有一个算法需要定义骨架,但其中的某些步骤可以延迟到子类中实现时,可以使用模板方法模式。
当需要在不同的子类中实现共同的行为,但具体的实现细节不同,可以使用模板方法模式。
下面是一个简单的模板方法模式示例,假设有一个制作咖啡的流程,其中包括冲泡咖啡、加入调料和装饰杯子等步骤:
java
// 抽象模板类:制作咖啡
abstract class CoffeeTemplate {
// 模板方法,定义制作咖啡的流程
public final void makeCoffee() {
boilWater();
brewCoffee();
pourInCup();
addCondiments();
decorateCup();
}
// 抽象方法,冲泡咖啡
protected abstract void brewCoffee();
// 具体方法,煮水
private void boilWater() {
System.out.println("煮水");
}
// 具体方法,倒入杯中
private void pourInCup() {
System.out.println("倒入杯中");
}
// 钩子方法,加入调料,默认为空实现,子类可以选择是否实现
protected void addCondiments() {}
// 钩子方法,装饰杯子,默认为空实现,子类可以选择是否实现
protected void decorateCup() {}
}
// 具体模板类:制作摩卡咖啡
class MochaCoffee extends CoffeeTemplate {
@Override
protected void brewCoffee() {
System.out.println("冲泡摩卡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入摩卡调料");
}
@Override
protected void decorateCup() {
System.out.println("装饰摩卡杯子");
}
}
// 具体模板类:制作拿铁咖啡
class LatteCoffee extends CoffeeTemplate {
@Override
protected void brewCoffee() {
System.out.println("冲泡拿铁咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入牛奶调料");
}
}
// 客户端代码
public class TemplateMethodExample {
public static void main(String[] args) {
CoffeeTemplate mochaCoffee = new MochaCoffee();
mochaCoffee.makeCoffee();
System.out.println("-----------------");
CoffeeTemplate latteCoffee = new LatteCoffee();
latteCoffee.makeCoffee();
}
}
观察者模式
java
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update();
}
// 具体观察者
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update() {
System.out.println(name + " 收到通知,进行更新操作");
}
}
// 被观察者接口
interface Subject {
void attach(Observer observer); // 添加观察者
void detach(Observer observer); // 移除观察者
void notifyObservers(); // 通知观察者
}
// 具体被观察者
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
// 具体业务逻辑,当状态变化时通知观察者
public void doSomething() {
// 状态变化...
System.out.println("被观察者状态发生变化");
notifyObservers();
}
}
public class ObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("观察者1");
Observer observer2 = new ConcreteObserver("观察者2");
subject.attach(observer1);
subject.attach(observer2);
subject.doSomething();
subject.detach(observer1); // 移除观察者1
subject.doSomething();
}
}
迭代器模式
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中各个元素,而不暴露该对象的内部表示。通过迭代器模式,客户端可以遍历一个聚合对象,而无需了解其内部结构。
使用场景:
- 当需要遍历一个聚合对象,并且希望在不暴露其内部结构的情况下访问其中的元素时,可以使用迭代器模式。例如,遍历一个集合或列表中的元素。
- 当希望提供一种统一的方法来访问不同类型的聚合对象时,迭代器模式也很有用。通过使用统一的迭代器接口,可以使客户端代码更加简洁。
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// 迭代器接口
interface MyIterator {
boolean hasNext();
Object next();
}
// 具体迭代器类
class ListIterator implements MyIterator {
private List<Integer> list;
private int index;
public ListIterator(List<Integer> list) {
this.list = list;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Object next() {
if (hasNext()) {
return list.get(index++);
}
return null;
}
}
// 聚合类:集合类 MyList
class MyList {
private List<Integer> list = new ArrayList<>();
public void add(int element) {
list.add(element);
}
public MyIterator iterator() {
return new ListIterator(list);
}
}
// 客户端代码
public class IteratorPatternExample {
public static void main(String[] args) {
MyList myList = new MyList();
myList.add(1);
myList.add(2);
myList.add(3);
MyIterator iterator = myList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的直接耦合关系。责任链模式将请求沿着一个链传递,直到有一个对象处理请求为止。
责任链模式通常包含以下几个角色:
- 抽象处理者(Handler): 定义了处理请求的接口,通常是一个抽象类或接口,其中包含一个指向下一个处理者的引用。
- 具体处理者(Concrete Handler): 继承自抽象处理者,实现了处理请求的具体逻辑,并决定是否处理请求或将请求传递给下一个处理者。
使用责任链模式可以实现请求的链式处理,每个处理者可以选择处理请求或将请求传递给下一个处理者。这样可以实现请求的动态分配和处理,增强系统的灵活性和可扩展性。
下面是一个简单的责任链模式示例,假设有一个报销审批系统,请求需要依次经过部门经理、财务部门和总经理审批,任何一个处理者都有权利决定是否批准请求:
java
// 抽象处理者:审批者
abstract class Approver {
protected Approver nextApprover; // 下一个处理者
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void processRequest(double amount); // 处理请求的抽象方法
}
// 具体处理者:部门经理
class DepartmentManager extends Approver {
@Override
public void processRequest(double amount) {
if (amount <= 1000) {
System.out.println("部门经理审批通过");
} else if (nextApprover != null) {
nextApprover.processRequest(amount); // 将请求传递给下一个处理者
}
}
}
// 具体处理者:财务部门
class FinancialDepartment extends Approver {
@Override
public void processRequest(double amount) {
if (amount <= 5000) {
System.out.println("财务部门审批通过");
} else if (nextApprover != null) {
nextApprover.processRequest(amount); // 将请求传递给下一个处理者
}
}
}
// 具体处理者:总经理
class GeneralManager extends Approver {
@Override
public void processRequest(double amount) {
System.out.println("总经理审批通过");
}
}
// 客户端代码
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// 创建具体处理者
Approver departmentManager = new DepartmentManager();
Approver financialDepartment = new FinancialDepartment();
Approver generalManager = new GeneralManager();
// 设置责任链
departmentManager.setNextApprover(financialDepartment);
financialDepartment.setNextApprover(generalManager);
// 发起审批请求
departmentManager.processRequest(800);
System.out.println("-----------------");
departmentManager.processRequest(2500);
System.out.println("-----------------");
departmentManager.processRequest(10000);
}
}
命令模式
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成对象,以便在不同的请求之间进行参数化操作,支持请求的排队、记录请求日志、撤销操作等。命令模式使得客户端可以对请求进行参数化,而无需知道请求的具体操作或接收者。
使用场景:
- 当需要将请求发送者和请求接收者解耦时,可以使用命令模式。例如,遥控器控制电视机,遥控器不需要知道电视机的具体操作,只需发送命令。
- 当希望支持请求的撤销、重做、排队等操作时,命令模式也很有用。通过将请求封装成对象,可以轻松地管理请求的状态和历史记录。
代码示例:
假设我们有一个简单的文本编辑器,支持撤销和重做操作,可以使用命令模式来实现:
java
// 命令接口:操作命令
interface Command {
void execute();
void undo();
}
// 具体命令类:插入文本命令
class InsertTextCommand implements Command {
private Editor editor;
private String text;
private int position;
public InsertTextCommand(Editor editor, String text, int position) {
this.editor = editor;
this.text = text;
this.position = position;
}
@Override
public void execute() {
editor.insertText(text, position);
}
@Override
public void undo() {
editor.deleteText(position, text.length());
}
}
// 具体命令类:删除文本命令
class DeleteTextCommand implements Command {
private Editor editor;
private String deletedText;
private int position;
public DeleteTextCommand(Editor editor, int position, int length) {
this.editor = editor;
this.position = position;
this.deletedText = editor.getText(position, length);
}
@Override
public void execute() {
editor.deleteText(position, deletedText.length());
}
@Override
public void undo() {
editor.insertText(deletedText, position);
}
}
// 接收者类:文本编辑器
class Editor {
private StringBuilder content = new StringBuilder();
public void insertText(String text, int position) {
content.insert(position, text);
System.out.println("Inserted: " + text);
}
public void deleteText(int position, int length) {
String deletedText = content.substring(position, position + length);
content.delete(position, position + length);
System.out.println("Deleted: " + deletedText);
}
public String getText(int position, int length) {
return content.substring(position, position + length);
}
}
// 请求者类:客户端代码
public class CommandPatternExample {
public static void main(String[] args) {
Editor editor = new Editor();
Command insertCommand = new InsertTextCommand(editor, "Hello", 0);
Command deleteCommand = new DeleteTextCommand(editor, 0, 5);
insertCommand.execute(); // 插入文本 "Hello"
deleteCommand.execute(); // 删除文本 "Hello"
deleteCommand.undo(); // 撤销删除操作
insertCommand.undo(); // 撤销插入操作
}
}
备忘录模式
备忘录模式(Memento Pattern)是一种行为型设计模式,它用于保存和恢复对象的状态,同时又不破坏对象的封装性。备忘录模式主要由三个角色组成:发起人(Originator)、备忘录(Memento)、管理者(Caretaker)。
- 发起人(Originator): 发起人是需要保存和恢复状态的对象,它可以创建备忘录对象,并在需要时使用备忘录对象恢复自身状态。
- 备忘录(Memento): 备忘录是保存发起人状态的对象,通常包含了发起人的部分或全部状态信息。
- 管理者(Caretaker): 管理者负责存储和管理备忘录对象,但并不直接访问备忘录的状态信息。
备忘录模式的核心思想是将对象的状态保存在备忘录对象中,从而实现状态的保存和恢复,同时又不暴露对象的内部状态。这样可以实现对对象状态的历史记录、撤销操作等功能。
下面是一个简单的备忘录模式示例,假设有一个文档编辑器,可以编辑文本内容,并且支持撤销操作:
java
// 备忘录类:文本编辑器备忘录
class TextEditorMemento {
private String content;
public TextEditorMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
// 发起人类:文本编辑器
class TextEditor {
private String content;
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
// 创建备忘录,保存当前状态
public TextEditorMemento createMemento() {
return new TextEditorMemento(content);
}
// 恢复状态,根据备忘录对象恢复状态
public void restoreMemento(TextEditorMemento memento) {
this.content = memento.getContent();
}
}
// 管理者类:文本编辑器历史管理
class HistoryManager {
private List<TextEditorMemento> history = new ArrayList<>();
// 添加备忘录到历史记录
public void addMemento(TextEditorMemento memento) {
history.add(memento);
}
// 获取指定索引的备忘录
public TextEditorMemento getMemento(int index) {
return history.get(index);
}
}
// 客户端代码
public class MementoPatternExample {
public static void main(String[] args) {
// 创建文本编辑器和历史管理者
TextEditor textEditor = new TextEditor();
HistoryManager historyManager = new HistoryManager();
// 编辑文本内容,并保存状态
textEditor.setContent("第一行内容");
historyManager.addMemento(textEditor.createMemento());
textEditor.setContent("第二行内容");
historyManager.addMemento(textEditor.createMemento());
// 恢复状态,撤销操作
textEditor.restoreMemento(historyManager.getMemento(0));
System.out.println("撤销后的内容:" + textEditor.getContent());
}
}
状态模式
状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态发生改变时改变其行为。状态模式将对象的各种状态封装成独立的类,并且允许对象在运行时根据其内部状态改变其行为,从而使得对象的状态转换和行为之间的关系更加清晰。
使用场景:
- 当一个对象的行为取决于其内部状态,并且在运行时需要根据状态改变行为时,可以使用状态模式。例如,自动售货机的状态可以包括有货、无货、投币等,不同状态下的行为是不同的。
- 当一个对象的状态转换比较复杂,且状态之间有明显的转换规则时,状态模式也很有用。通过将状态和状态转换封装成独立的类,可以简化状态之间的转换逻辑。
代码示例:
假设我们有一个简单的文档编辑器,支持草稿、审核中和已发布三种状态,可以使用状态模式来实现:
java
// 状态接口:文档状态
interface DocumentState {
void handle(Document document);
}
// 具体状态类:草稿状态
class DraftState implements DocumentState {
@Override
public void handle(Document document) {
System.out.println("Document is in Draft state");
// 可以执行草稿状态下的操作
}
}
// 具体状态类:审核中状态
class ReviewState implements DocumentState {
@Override
public void handle(Document document) {
System.out.println("Document is in Review state");
// 可以执行审核中状态下的操作
}
}
// 具体状态类:已发布状态
class PublishedState implements DocumentState {
@Override
public void handle(Document document) {
System.out.println("Document is in Published state");
// 可以执行已发布状态下的操作
}
}
// 上下文类:文档编辑器
class Document {
private DocumentState state;
public void setState(DocumentState state) {
this.state = state;
}
public void handleRequest() {
state.handle(this);
}
}
// 客户端代码
public class StatePatternExample {
public static void main(String[] args) {
Document document = new Document();
document.setState(new DraftState());
document.handleRequest(); // 输出:Document is in Draft state
document.setState(new ReviewState());
document.handleRequest(); // 输出:Document is in Review state
document.setState(new PublishedState());
document.handleRequest(); // 输出:Document is in Published state
}
}
访问者模式
访问者模式(Visitor Pattern)是一种行为型设计模式,它可以在不改变被访问元素(数据结构)的前提下,定义对元素的新操作。访问者模式将数据结构与操作分离,使得新增操作变得更加灵活,同时也符合开闭原则。
访问者模式包含以下几个角色:
- 访问者(Visitor): 定义了对数据结构中各元素的访问操作接口,通常是一个接口或抽象类,包含了对不同元素的不同操作方法。
- 具体访问者(Concrete Visitor): 实现了访问者接口,对数据结构中的具体元素进行具体操作。
- 元素(Element): 定义了数据结构的接口或抽象类,提供一个 accept 方法用于接受访问者的访问。
- 具体元素(Concrete Element): 实现了元素接口,表示数据结构中的具体元素,提供 accept 方法的具体实现。
- 对象结构(Object Structure): 包含了一组元素,提供一个接口让访问者可以访问其中的元素。
访问者模式的核心思想是将数据结构与操作解耦,使得新增操作变得更加灵活,同时也方便对数据结构中的元素进行统一的操作。
下面是一个简单的访问者模式示例,假设有一个购物车中包含了多种商品,我们需要计算不同类型商品的总价和打折价:
java
// 访问者接口:商品访问者
interface Visitor {
void visit(Book book);
void visit(Fruit fruit);
}
// 具体访问者:实现对商品的操作
class PriceCalculator implements Visitor {
private double totalPrice = 0;
public double getTotalPrice() {
return totalPrice;
}
@Override
public void visit(Book book) {
totalPrice += book.getPrice();
}
@Override
public void visit(Fruit fruit) {
totalPrice += fruit.getPrice() * fruit.getWeight() * 0.8; // 8折打折
}
}
// 元素接口:商品元素
interface Element {
void accept(Visitor visitor);
}
// 具体元素:书籍
class Book implements Element {
private double price;
public Book(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 具体元素:水果
class Fruit implements Element {
private double price;
private double weight;
public Fruit(double price, double weight) {
this.price = price;
this.weight = weight;
}
public double getPrice() {
return price;
}
public double getWeight() {
return weight;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 对象结构:购物车
class ShoppingCart {
private List<Element> items = new ArrayList<>();
public void addItem(Element item) {
items.add(item);
}
public void accept(Visitor visitor) {
for (Element item : items) {
item.accept(visitor);
}
}
}
// 客户端代码
public class VisitorPatternExample {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Book(50));
cart.addItem(new Fruit(5, 2)); // 水果单价5元,重量2kg
PriceCalculator calculator = new PriceCalculator();
cart.accept(calculator);
System.out.println("商品总价:" + calculator.getTotalPrice());
}
}
中介者模式
中介者模式(Mediator Pattern)是一种行为型设计模式,它用于降低多个对象之间的耦合性,通过引入一个中介者对象来协调对象之间的交互。中介者模式可以使得对象之间的通信更加简单明了,并且减少对象之间的直接依赖关系。
使用场景:
- 当一个系统中存在多个对象之间复杂的交互关系,并且这些对象之间的耦合度较高时,可以使用中介者模式。例如,多个部件之间需要进行相互通信来完成某项任务。
- 当希望减少对象之间的直接依赖关系,并且希望通过一个中介者对象来统一管理对象之间的交互时,中介者模式也很有用。例如,一个 MVC 架构中的控制器可以作为中介者来管理视图和模型之间的交互。
代码示例:
假设我们有一个简单的聊天室程序,包含多个用户和一个聊天室中介者来管理用户之间的消息传递,可以使用中介者模式来实现:
java
import java.util.ArrayList;
import java.util.List;
// 中介者接口:聊天室中介者
interface ChatMediator {
void sendMessage(User sender, String message);
}
// 具体中介者类:聊天室
class ChatRoom implements ChatMediator {
private List<User> users;
public ChatRoom() {
this.users = new ArrayList<>();
}
public void addUser(User user) {
users.add(user);
}
@Override
public void sendMessage(User sender, String message) {
for (User user : users) {
if (user != sender) {
user.receiveMessage(message);
}
}
}
}
// 抽象同事类:用户
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void sendMessage(String message);
public abstract void receiveMessage(String message);
}
// 具体同事类:普通用户
class NormalUser extends User {
public NormalUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(String message) {
System.out.println(name + " sends message: " + message);
mediator.sendMessage(this, message);
}
@Override
public void receiveMessage(String message) {
System.out.println(name + " receives message: " + message);
}
}
// 客户端代码
public class MediatorPatternExample {
public static void main(String[] args) {
ChatMediator mediator = new ChatRoom();
User user1 = new NormalUser(mediator, "Alice");
User user2 = new NormalUser(mediator, "Bob");
User user3 = new NormalUser(mediator, "Charlie");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
user1.sendMessage("Hello, everyone!");
}
}