单例模式(Singleton Pattern)是一种常用的软件设计模式,属于创建型模式之一。它的目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在需要频繁访问且创建代价高的对象,或者需要控制资源访问点的情况下非常有用。
核心原理
单例模式的核心是在类内部实现对自身实例的唯一性和对这个实例的全局访问。通常,单例类会将其构造函数设为私有,防止外部直接实例化,并提供一个静态方法或属性作为全局访问点。
优点
缺点
适用场景
Java示例
以下是几种常见的单例模式实现:
饿汉式(静态内部类)
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
懒汉式(线程安全)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
枚举单例(推荐)
public enum Singleton {
INSTANCE;
public void someMethod() {
// ...
}
}
枚举单例是Java中实现单例模式的一种简单且高效的方式,它天然支持序列化机制,防止反射攻击,同时保证线程安全。以上示例可通过 Singleton.INSTANCE 获取 Singleton的单例实例。
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了创建对象的最佳方式。在工厂方法模式中,一个抽象工厂类定义了一个创建对象的接口,但允许子类决定实例化哪一个类。工厂方法让类的实例化延迟到子类进行。
核心组件
优点
缺点
适用场景
Java示例
下面是一个简单的Java示例,展示如何使用工厂方法模式创建不同类型的按钮:
// 抽象产品
interface Button {
void display();
}
// 具体产品1
class WindowsButton implements Button {
@Override
public void display() {
System.out.println("Windows style button");
}
}
// 具体产品2
class MacButton implements Button {
@Override
public void display() {
System.out.println("Mac style button");
}
}
// 抽象工厂
abstract class GUIFactory {
abstract Button createButton();
}
// 具体工厂1
class WindowsFactory extends GUIFactory {
@Override
Button createButton() {
return new WindowsButton();
}
}
// 具体工厂2
class MacFactory extends GUIFactory {
@Override
Button createButton() {
return new MacButton();
}
}
// 客户端代码
public class Application {
private Button button;
public Application(GUIFactory factory) {
button = factory.createButton();
}
public void paint() {
button.display();
}
public static void main(String[] args) {
Application app = new Application(new MacFactory());
app.paint(); // 输出: Mac style button
}
}
在这个例子中,GUIFactory 是抽象工厂,WindowsFactory 和 MacFactory 是具体工厂,它们分别创建 WindowsButton 和 MacButton。客户端 Application 类通过传入不同的具体工厂来创建不同风格的按钮。这样,当需要支持新的操作系统时,只需要添加一个新的具体工厂类即可,而不需要修改 Application 类。
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种接口,用于创建一系列相关的或相互依赖的对象,而无需指定它们具体的类。此模式特别适用于创建产品族,即一组相关或相互依赖的对象。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个图形界面库,需要创建不同操作系统的窗口和按钮。我们可以使用抽象工厂模式来实现:
// 抽象产品接口
interface Window {}
interface Button {}
// 具体产品实现
class WindowsWindow implements Window {}
class MacOSWindow implements Window {}
class WindowsButton implements Button {}
class MacOSButton implements Button {}
// 抽象工厂接口
interface GUIFactory {
Window createWindow();
Button createButton();
}
// 具体工厂实现
class WindowsFactory implements GUIFactory {
@Override
public Window createWindow() {
return new WindowsWindow();
}
@Override
public Button createButton() {
return new WindowsButton();
}
}
class MacFactory implements GUIFactory {
@Override
public Window createWindow() {
return new MacOSWindow();
}
@Override
public Button createButton() {
return new MacOSButton();
}
}
// 客户端代码
public class Application {
private Window window;
private Button button;
public Application(GUIFactory factory) {
this.window = factory.createWindow();
this.button = factory.createButton();
}
public void paint() {
window.show();
button.click();
}
public static void main(String[] args) {
Application app = new Application(new MacFactory());
app.paint();
}
}
在这个例子中,GUIFactory 是抽象工厂,WindowsFactory 和 MacFactory 是具体工厂,它们分别创建 WindowsWindow 和 MacOSWindow 以及对应的按钮。客户端 Application 类通过传入不同的具体工厂来创建不同操作系统的窗口和按钮,从而支持跨平台的界面组件。
建造者模式(Builder Pattern)是一种创建型设计模式,它允许你逐步构建一个复杂的对象。这种模式将构建过程与表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于创建那些拥有多个可选组成部分的复杂对象,而且这些组成部分的构建顺序和方式可能会影响最终产品的表现形式。
核心组件
优点
缺点
适用场景
Java示例
假设我们要创建一个汉堡,汉堡可以有多种配料,我们可以使用建造者模式来实现:
// 产品 - 汉堡
class Burger {
private String bread;
private List ingredients;
public Burger(String bread) {
this.bread = bread;
this.ingredients = new ArrayList<>();
}
public void addIngredient(String ingredient) {
ingredients.add(ingredient);
}
@Override
public String toString() {
return "Burger{" +
"bread='" + bread + '\'' +
", ingredients=" + ingredients +
'}';
}
}
// 抽象建造者
interface BurgerBuilder {
void setBread();
void addIngredients(String... ingredients);
Burger getResult();
}
// 具体建造者 - 素食汉堡建造者
class VeggieBurgerBuilder implements BurgerBuilder {
private Burger burger;
public VeggieBurgerBuilder() {
burger = new Burger("Whole wheat bun");
}
@Override
public void setBread() {
// 不需要做任何事情,因为已经在构造函数中设置了面包
}
@Override
public void addIngredients(String... ingredients) {
for (String ingredient : ingredients) {
burger.addIngredient(ingredient);
}
}
@Override
public Burger getResult() {
return burger;
}
}
// 具体建造者 - 肉汉堡建造者
class MeatBurgerBuilder implements BurgerBuilder {
private Burger burger;
public MeatBurgerBuilder() {
burger = new Burger("Brioche bun");
}
@Override
public void setBread() {
// 不需要做任何事情,因为已经在构造函数中设置了面包
}
@Override
public void addIngredients(String... ingredients) {
for (String ingredient : ingredients) {
burger.addIngredient(ingredient);
}
}
@Override
public Burger getResult() {
return burger;
}
}
// 指挥者
class Director {
public Burger construct(BurgerBuilder builder, String... ingredients) {
builder.setBread();
builder.addIngredients(ingredients);
return builder.getResult();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Director director = new Director();
BurgerBuilder veggieBuilder = new VeggieBurgerBuilder();
BurgerBuilder meatBuilder = new MeatBurgerBuilder();
Burger veggieBurger = director.construct(veggieBuilder, "Lettuce", "Tomato", "Avocado");
Burger meatBurger = director.construct(meatBuilder, "Beef patty", "Cheese", "Onion");
System.out.println(veggieBurger);
System.out.println(meatBurger);
}
}
在这个例子中,Burger 是产品,BurgerBuilder 是抽象建造者,VeggieBurgerBuilder 和 MeatBurgerBuilder 是具体建造者,Director 是指挥者。客户端通过指挥者调用具体建造者来创建不同类型的汉堡。
原型模式(Prototype Pattern)是一种创建型设计模式,它使用已有的实例作为原型,通过复制该原型对象来创建新的对象,而不是通过实例化类来创建对象。这种模式允许对象的克隆,即创建一个对象的副本,而无需知道其具体类型。原型模式的主要优势在于它可以避免构造函数的约束,提高创建对象的效率,尤其是在创建对象成本较高的情况下。
核心组件
优点
缺点
适用场景
Java示例
在Java中,Cloneable 接口和 clone() 方法可以用来实现原型模式。下面是一个简单的Java示例:
import java.util.Date;
// 抽象原型
interface Prototype extends Cloneable {
T clone();
}
// 具体原型
class Person implements Prototype {
private String name;
private Date birthDate;
public Person(String name, Date birthDate) {
this.name = name;
this.birthDate = birthDate;
}
public String getName() {
return name;
}
public Date getBirthDate() {
return birthDate;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// 重写 clone 方法以实现深拷贝
public Person clone() {
try {
Person clonedPerson = (Person) super.clone();
clonedPerson.birthDate = (Date) this.birthDate.clone();
return clonedPerson;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.toString());
}
}
}
// 客户端代码
public class PrototypeDemo {
public static void main(String[] args) {
Date birthDate = new Date();
Person person = new Person("John Doe", birthDate);
Person clonedPerson = person.clone();
System.out.println(person.getName() + ": " + person.getBirthDate());
System.out.println(clonedPerson.getName() + ": " + clonedPerson.getBirthDate());
}
}
在这个例子中,Person 类实现了 Prototype 接口,并重写了 clone() 方法以确保深拷贝。这样,当创建 Person 的克隆时,birthDate 字段也会被独立复制,避免了对象之间的引用共享。
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间可以协同工作。适配器模式的主要目的是将一个类的接口转换成客户希望的另一个接口,从而使原本因接口不兼容而不能一起工作的那些类可以一起工作。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个旧系统中的类 LegacyAudioPlayer 只能播放 MP3 文件,现在我们需要让它能够播放 WAV 文件,但是我们不想修改 LegacyAudioPlayer 的源代码。我们可以使用适配器模式来实现:
// 目标接口
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 适配者类
class LegacyAudioPlayer {
public void playMP3(String fileName) {
System.out.println("Playing MP3 file. Name: " + fileName);
}
}
// 适配器类
class MediaAdapter implements MediaPlayer {
private LegacyAudioPlayer legacyAudioPlayer;
public MediaAdapter() {
this.legacyAudioPlayer = new LegacyAudioPlayer();
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
legacyAudioPlayer.playMP3(fileName);
} else if (audioType.equalsIgnoreCase("wav")) {
// 假设这里有一个转换WAV到MP3的方法
String mp3FileName = convertWavToMp3(fileName);
legacyAudioPlayer.playMP3(mp3FileName);
}
}
private String convertWavToMp3(String fileName) {
// 这里可以是转换逻辑
return "converted-" + fileName + ".mp3";
}
}
// 客户端代码
public class AdapterPatternDemo {
public static void main(String[] args) {
MediaPlayer mediaAdapter = new MediaAdapter();
mediaAdapter.play("mp3", "song.mp3");
mediaAdapter.play("wav", "song.wav");
}
}
在这个例子中,MediaPlayer 是目标接口,LegacyAudioPlayer 是适配者,MediaAdapter 是适配器。适配器持有 LegacyAudioPlayer 的实例,并将 MediaPlayer 的 play 方法调用适当地转换为 LegacyAudioPlayer 的 playMP3 方法。如果需要播放 WAV 文件,适配器会先将文件转换为 MP3 格式,然后调用 LegacyAudioPlayer 的方法。
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与其实现部分分离,使它们都可以独立地变化。桥接模式的主要目的是解耦一个抽象及其实现,以便两者可以独立地演变。这种模式通过提供一个桥接,将抽象与实现解耦,从而使得抽象和实现可以独立地扩展。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个绘图系统,需要绘制不同形状(如圆形和矩形)并且这些形状可以用不同的颜色来渲染。我们可以使用桥接模式来实现:
// 实现者接口
interface Renderer {
void drawCircle(float radius);
}
// 具体实现者 - 使用向量图形渲染
class VectorRenderer implements Renderer {
@Override
public void drawCircle(float radius) {
System.out.println("Drawing a circle [VectorRenderer: " + radius + "]");
}
}
// 具体实现者 - 使用位图图形渲染
class RasterRenderer implements Renderer {
@Override
public void drawCircle(float radius) {
System.out.println("Drawing a circle [RasterRenderer: " + radius + "]");
}
}
// 抽象类
abstract class Shape {
protected Renderer renderer;
public Shape(Renderer renderer) {
this.renderer = renderer;
}
public abstract void draw();
}
// 细化抽象 - 圆形
class Circle extends Shape {
private float radius;
public Circle(Renderer renderer, float radius) {
super(renderer);
this.radius = radius;
}
@Override
public void draw() {
renderer.drawCircle(radius);
}
}
// 客户端代码
public class BridgePatternDemo {
public static void main(String[] args) {
Renderer rasterRenderer = new RasterRenderer();
Renderer vectorRenderer = new VectorRenderer();
Shape circle1 = new Circle(rasterRenderer, 10);
circle1.draw();
Shape circle2 = new Circle(vectorRenderer, 10);
circle2.draw();
}
}
在这个例子中,Renderer 是实现者接口,VectorRenderer 和 RasterRenderer 是具体实现者,Shape 是抽象类,Circle 是细化抽象。Shape 类持有一个 Renderer 对象的引用,这样就可以在运行时选择不同的渲染方式。当我们创建 Circle 对象时,可以选择使用 RasterRenderer 或 VectorRenderer 来渲染,从而实现了渲染方式和形状的解耦。
组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树状结构来表示“部分-整体”的层次结构。组合模式使得客户端可以一致地处理单个对象和组合对象,即以相同的方式操作叶子对象和树枝对象。
核心组件
优点
缺点
适用场景
Java示例
假设我们正在设计一个文件系统,其中文件夹可以包含其他文件夹和文件,我们可以使用组合模式来实现:
// Component接口
interface FileSystemItem {
void add(FileSystemItem item);
void remove(FileSystemItem item);
FileSystemItem getChild(int i);
void printList();
}
// Leaf - 文件
class File implements FileSystemItem {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void add(FileSystemItem item) {
// 文件不能包含其他项
throw new UnsupportedOperationException("Cannot add to a file.");
}
@Override
public void remove(FileSystemItem item) {
// 文件不能包含其他项
throw new UnsupportedOperationException("Cannot remove from a file.");
}
@Override
public FileSystemItem getChild(int i) {
// 文件不能包含其他项
throw new UnsupportedOperationException("Cannot get child of a file.");
}
@Override
public void printList() {
System.out.println("File: " + name);
}
}
// Composite - 文件夹
class Directory implements FileSystemItem {
private String name;
private List children = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
@Override
public void add(FileSystemItem item) {
children.add(item);
}
@Override
public void remove(FileSystemItem item) {
children.remove(item);
}
@Override
public FileSystemItem getChild(int i) {
return children.get(i);
}
@Override
public void printList() {
System.out.println("Directory: " + name);
for (FileSystemItem item : children) {
item.printList();
}
}
}
// 客户端代码
public class CompositePatternDemo {
public static void main(String[] args) {
FileSystemItem root = new Directory("root");
FileSystemItem subDir1 = new Directory("subDir1");
FileSystemItem subDir2 = new Directory("subDir2");
FileSystemItem file1 = new File("file1.txt");
FileSystemItem file2 = new File("file2.txt");
root.add(subDir1);
root.add(subDir2);
subDir1.add(file1);
subDir2.add(file2);
root.printList();
}
}
在这个例子中,FileSystemItem 是Component接口,File 和 Directory 分别是Leaf和Composite。Directory 可以包含其他 FileSystemItem 对象,而 File 不能。客户端代码可以一致地处理 File 和 Directory,调用它们的 printList 方法来打印文件系统的内容。
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不修改原类代码的情况下动态地给对象添加新的功能。装饰器模式通过使用对象的组合而非继承来达到扩展功能的目的,使得系统更加灵活,可以动态地给一个对象添加职责。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个饮料基类,我们想动态地给饮料添加不同的配料,如糖、奶泡等。下面是一个使用装饰器模式的例子:
// Component
interface Beverage {
String getDescription();
double cost();
}
// ConcreteComponent
class Espresso implements Beverage {
@Override
public String getDescription() {
return "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
// Decorator
abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription();
}
}
// ConcreteDecorator
class Mocha implements CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public double cost() {
return beverage.cost() + 0.20;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
}
class Whip implements CondimentDecorator {
public Whip(Beverage beverage) {
super(beverage);
}
@Override
public double cost() {
return beverage.cost() + 0.10;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
}
// 客户端代码
public class DecoratorPatternDemo {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
beverage = new Mocha(new Whip(new Espresso()));
System.out.println(beverage.getDescription() + " $" + beverage.cost());
}
}
在这个例子中,Beverage 是Component接口,Espresso 是具体组件,CondimentDecorator 是装饰器基类,Mocha 和 Whip 是具体装饰器。装饰器持有被装饰对象的引用,并在其方法中调用被装饰对象的方法,同时可以添加自己的行为。这样,我们可以在运行时动态地给饮料添加不同的配料,而无需修改饮料的原始代码。
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一群接口。外观模式的主要目的是简化一个复杂系统的使用,通过提供一个更高层次的接口,使得这个子系统更加容易被使用。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个家庭自动化系统,包括灯光控制、温度控制和安全系统。我们可以使用外观模式来简化对这些子系统的使用:
// 子系统 - 灯光控制
class LightControl {
public void turnOn() {
System.out.println("Lights are on.");
}
public void turnOff() {
System.out.println("Lights are off.");
}
}
// 子系统 - 温度控制
class TemperatureControl {
public void setTemperature(int temperature) {
System.out.println("Setting temperature to " + temperature + " degrees.");
}
}
// 子系统 - 安全系统
class SecuritySystem {
public void arm() {
System.out.println("Security system is armed.");
}
public void disarm() {
System.out.println("Security system is disarmed.");
}
}
// Facade
class HomeAutomationFacade {
private LightControl lightControl = new LightControl();
private TemperatureControl temperatureControl = new TemperatureControl();
private SecuritySystem securitySystem = new SecuritySystem();
public void goodNight() {
lightControl.turnOff();
temperatureControl.setTemperature(18);
securitySystem.arm();
}
public void goodMorning() {
lightControl.turnOn();
temperatureControl.setTemperature(22);
securitySystem.disarm();
}
}
// 客户端代码
public class FacadePatternDemo {
public static void main(String[] args) {
HomeAutomationFacade facade = new HomeAutomationFacade();
// 使用外观模式简化操作
facade.goodNight();
System.out.println("---");
facade.goodMorning();
}
}
在这个例子中,HomeAutomationFacade 是外观类,它持有LightControl、TemperatureControl和SecuritySystem的引用。客户端可以通过调用HomeAutomationFacade的goodNight和goodMorning方法来简化对家庭自动化系统的使用,而无需直接与子系统交互。
享元模式(Flyweight Pattern)是一种结构型设计模式,它用于减少创建大量相似对象所需的内存消耗。享元模式通过共享尽可能多的数据来支持大量细粒度的对象,通常用于处理大量相似对象的场景,尤其是当这些对象的大部分状态可以外部化时。
核心组件
优点
缺点
适用场景
Java示例
假设我们正在开发一个文本编辑器,需要显示大量的字符,每个字符可以有不同的字体、大小和颜色。为了节省内存,我们可以使用享元模式来共享字符的内部状态(如字体、大小),而将颜色作为外部状态。
import java.util.HashMap;
import java.util.Map;
// Flyweight interface
interface CharacterFlyweight {
void display(int x, int y, char character, int color);
}
// UnsharedConcreteFlyweight
class ConcreteCharacterFlyweight implements CharacterFlyweight {
private final String font;
private final int size;
public ConcreteCharacterFlyweight(String font, int size) {
this.font = font;
this.size = size;
}
@Override
public void display(int x, int y, char character, int color) {
System.out.printf("Displaying character '%c' at (%d, %d) with font '%s', size %d, and color %d%n",
character, x, y, font, size, color);
}
}
// FlyweightFactory
public class CharacterFlyweightFactory {
private Map flyweights = new HashMap<>();
public CharacterFlyweight getCharacterFlyweight(String font, int size) {
String key = font + "-" + size;
CharacterFlyweight flyweight = flyweights.get(key);
if (flyweight == null) {
flyweight = new ConcreteCharacterFlyweight(font, size);
flyweights.put(key, flyweight);
}
return flyweight;
}
}
// Client code
public class FlyweightPatternDemo {
public static void main(String[] args) {
CharacterFlyweightFactory factory = new CharacterFlyweightFactory();
CharacterFlyweight a = factory.getCharacterFlyweight("Arial", 12);
CharacterFlyweight b = factory.getCharacterFlyweight("Arial", 12);
CharacterFlyweight c = factory.getCharacterFlyweight("Times New Roman", 14);
a.display(10, 10, 'A', 0xFF0000); // Red
b.display(20, 20, 'B', 0x00FF00); // Green
c.display(30, 30, 'C', 0x0000FF); // Blue
}
}
在这个例子中,CharacterFlyweight 是享元接口,ConcreteCharacterFlyweight 是具体享元,CharacterFlyweightFactory 是享元工厂。字体和大小作为内部状态在享元对象中存储,而颜色作为外部状态在使用时传入。通过享元工厂,相同的字体和大小组合只会创建一次享元对象,从而节省了内存。
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理以控制对这个对象的访问。代理模式允许程序员在访问一个类的实例之前,增加一些额外的操作,比如权限检查、日志记录、缓存等。
核心组件
优点
缺点
适用场景
Java示例
下面是一个使用静态代理的Java示例,假设我们有一个图像加载和显示的场景,其中代理可以缓存图像,避免重复加载。
// Subject
interface Image {
void display();
}
// RealSubject
class RealImage implements Image {
private final String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(filename);
}
private void loadFromDisk(String filename) {
System.out.println("Loading image: " + filename);
}
@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// Proxy
class ProxyImage implements Image {
private RealImage realImage;
private final String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// Client code
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像第一次加载
image.display();
// 再次显示图像,这次不会重新加载
image.display();
}
}
在这个例子中,Image 是主题接口,RealImage 是真实主题,ProxyImage 是代理。ProxyImage 在第一次调用display方法时会创建并加载RealImage,之后的调用则直接使用已加载的RealImage对象,避免了重复加载,实现了懒加载的效果。
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
核心组件
优点
缺点
适用场景
Java示例
假设在一个公司中,员工提交请假申请,根据请假天数,申请可能需要不同级别的管理者批准。我们可以使用责任链模式来处理这个场景:
// Handler
abstract class LeaveRequestHandler {
protected LeaveRequestHandler nextHandler;
public LeaveRequestHandler setNext(LeaveRequestHandler handler) {
nextHandler = handler;
return handler;
}
public abstract void handleRequest(int days);
}
// ConcreteHandler
class TeamLead extends LeaveRequestHandler {
@Override
public void handleRequest(int days) {
if (days <= 2) {
System.out.println("Team Lead approved leave for " + days + " days.");
} else {
if (nextHandler != null) {
nextHandler.handleRequest(days);
} else {
System.out.println("No handler available for " + days + " days leave request.");
}
}
}
}
class Manager extends LeaveRequestHandler {
@Override
public void handleRequest(int days) {
if (days <= 5) {
System.out.println("Manager approved leave for " + days + " days.");
} else {
if (nextHandler != null) {
nextHandler.handleRequest(days);
} else {
System.out.println("No handler available for " + days + " days leave request.");
}
}
}
}
class Director extends LeaveRequestHandler {
@Override
public void handleRequest(int days) {
System.out.println("Director approved leave for " + days + " days.");
}
}
// Client code
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
LeaveRequestHandler teamLead = new TeamLead();
LeaveRequestHandler manager = new Manager();
LeaveRequestHandler director = new Director();
teamLead.setNext(manager).setNext(director);
teamLead.handleRequest(1); // Should be handled by Team Lead
teamLead.handleRequest(3); // Should be handled by Manager
teamLead.handleRequest(6); // Should be handled by Director
}
}
在这个例子中,LeaveRequestHandler 是处理器接口,TeamLead、Manager 和 Director 是具体处理器。请求(请假天数)沿着责任链传递,直到找到合适的处理器。如果请求没有被任何一个处理器处理,那么它将不会得到响应
命令模式(Command Pattern)是一种行为设计模式,它将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个简单的遥控器,可以控制不同的设备,如电灯和电视,执行打开和关闭的操作。我们可以使用命令模式来设计这个系统:
// Command interface
interface Command {
void execute();
}
// Receiver classes
class Light {
public void on() {
System.out.println("Light is on");
}
public void off() {
System.out.println("Light is off");
}
}
class TV {
public void on() {
System.out.println("TV is on");
}
public void off() {
System.out.println("TV is off");
}
}
// ConcreteCommand classes
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
class TVOnCommand implements Command {
private TV tv;
public TVOnCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.on();
}
}
class TVOffCommand implements Command {
private TV tv;
public TVOffCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.off();
}
}
// Invoker class
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// Client code
public class CommandPatternDemo {
public static void main(String[] args) {
Light light = new Light();
TV tv = new TV();
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(new LightOnCommand(light));
remoteControl.pressButton();
remoteControl.setCommand(new TVOnCommand(tv));
remoteControl.pressButton();
remoteControl.setCommand(new LightOffCommand(light));
remoteControl.pressButton();
remoteControl.setCommand(new TVOffCommand(tv));
remoteControl.pressButton();
}
}
在这个例子中,Command 是命令接口,LightOnCommand、LightOffCommand、TVOnCommand 和 TVOffCommand 是具体命令,Light 和 TV 是接收者,RemoteControl 是调用者。通过这种方式,我们可以动态地向遥控器添加不同的命令,而且可以轻松地扩展系统以支持更多的设备和操作。
解释器模式(Interpreter Pattern)是一种行为设计模式,它允许你定义一个语言的文法,并且建立一个解释器来解释该语言中的句子。这种模式可以用于编译器、查询语言解析器等领域,其中需要解析特定的语法规则。
核心组件
优点
缺点
适用场景
Java示例
假设我们需要解析一个简单的算术表达式语言,其中包含加法和减法运算。我们可以使用解释器模式来实现:
// AbstractExpression
abstract class Expression {
abstract int interpret(Context context);
}
// TerminalExpression
class NumberExpression extends Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
int interpret(Context context) {
return number;
}
}
// NonterminalExpression
class AdditionExpression extends Expression {
private Expression left;
private Expression right;
public AdditionExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
class SubtractionExpression extends Expression {
private Expression left;
private Expression right;
public SubtractionExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
// Context
class Context {
// In this simple example, the context is not used.
}
// Client code
public class InterpreterPatternDemo {
public static void main(String[] args) {
Expression expr1 = new AdditionExpression(
new NumberExpression(5),
new NumberExpression(10)
);
System.out.println("5 + 10 = " + expr1.interpret(new Context()));
Expression expr2 = new SubtractionExpression(
new NumberExpression(20),
new NumberExpression(5)
);
System.out.println("20 - 5 = " + expr2.interpret(new Context()));
}
}
在这个例子中,Expression 是抽象表达式,NumberExpression 是终结表达式,AdditionExpression 和 SubtractionExpression 是非终结表达式,它们分别代表数字、加法和减法。Context 类在这里没有实际用途,但在更复杂的应用中,它可能包含解释器需要的额外信息。通过这种方式,我们可以构建和解析算术表达式树,并计算其结果。
迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种方法来访问聚合对象(如列表、集合等)的元素,而无需暴露其底层表示。迭代器模式允许客户端顺序访问聚合对象的元素,而无需知道聚合对象的内部结构。
核心组件
优点
缺点
适用场景
Java示例
在Java中,Iterable接口和Iterator接口已经提供了迭代器模式的实现。这里我们创建一个简单的例子,展示如何手动实现迭代器模式:
// Aggregate
interface Aggregate {
Iterator createIterator();
}
// ConcreteAggregate
class MyList implements Aggregate {
private List items = new ArrayList<>();
public void add(String item) {
items.add(item);
}
@Override
public Iterator createIterator() {
return new MyIterator(items);
}
}
// Iterator
interface Iterator {
boolean hasNext();
Object next();
}
// ConcreteIterator
class MyIterator implements Iterator {
private List items;
private int position = 0;
public MyIterator(List items) {
this.items = items;
}
@Override
public boolean hasNext() {
return position < items.size();
}
@Override
public Object next() {
if (this.hasNext()) {
return items.get(position++);
}
return null;
}
}
// Client code
public class IteratorPatternDemo {
public static void main(String[] args) {
MyList list = new MyList();
list.add("Item 1");
list.add("Item 2");
list.add("Item 3");
Iterator iterator = list.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
在这个例子中,MyList 是具体聚合,它实现了Aggregate接口,并提供了一个方法来创建迭代器。MyIterator 是具体迭代器,它实现了Iterator接口,负责遍历MyList中的元素。客户端代码使用迭代器遍历MyList中的元素,而不需要知道MyList是如何存储这些元素的。
中介者模式(Mediator Pattern)是一种行为设计模式,它定义了对象间的一种间接通信机制,使得对象之间通过一个共享的中介者对象进行通信,而不是直接相互引用。这样可以减少对象间的依赖关系,使它们之间松耦合。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个聊天室系统,其中用户可以发送消息给其他用户。我们使用中介者模式来管理用户之间的消息传递:
// Mediator interface
interface ChatRoom {
void sendMessage(String msg, User user);
}
// ConcreteMediator
class SimpleChatRoom implements ChatRoom {
@Override
public void sendMessage(String msg, User user) {
System.out.println(user.getName() + ": " + msg);
}
}
// Colleague interface
interface User {
String getName();
void receiveMessage(String msg);
}
// ConcreteColleague
class SimpleUser implements User {
private String name;
private ChatRoom chatRoom;
public SimpleUser(String name, ChatRoom chatRoom) {
this.name = name;
this.chatRoom = chatRoom;
}
@Override
public String getName() {
return name;
}
public void sendMessage(String msg) {
chatRoom.sendMessage(msg, this);
}
@Override
public void receiveMessage(String msg) {
System.out.println(name + " received: " + msg);
}
}
// Client code
public class MediatorPatternDemo {
public static void main(String[] args) {
ChatRoom chatRoom = new SimpleChatRoom();
User john = new SimpleUser("John", chatRoom);
User jane = new SimpleUser("Jane", chatRoom);
john.sendMessage("Hello Jane!");
jane.sendMessage("Hi John!");
}
}
在这个例子中,ChatRoom 是中介者接口,SimpleChatRoom 是具体中介者,它负责转发消息。User 是同事接口,SimpleUser 是具体同事,它们通过中介者发送和接收消息。客户端代码创建了两个用户并让它们通过中介者发送消息。这种方式确保了用户之间没有直接的依赖关系,所有的通信都通过中介者进行。
备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不破坏封装性的前提下捕获和恢复一个对象的内部状态。这种模式经常用于实现撤销(undo)功能,或者在对象需要保存其状态以供以后恢复时使用。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个文本编辑器,需要保存文档的不同版本,以便用户可以随时恢复到之前的版本:
// Memento
class DocumentMemento {
private final String content;
public DocumentMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
// Originator
class Document {
private String content;
public Document(String content) {
this.content = content;
}
public void setContent(String content) {
this.content = content;
}
public DocumentMemento save() {
return new DocumentMemento(this.content);
}
public void restore(DocumentMemento memento) {
this.content = memento.getContent();
}
@Override
public String toString() {
return "Document{" +
"content='" + content + '\'' +
'}';
}
}
// Caretaker
class DocumentHistory {
private List mementos = new ArrayList<>();
private int current = -1;
public void addMemento(DocumentMemento memento) {
if (this.current >= 0) {
this.mementos.subList(this.current + 1, this.mementos.size()).clear();
}
this.mementos.add(memento);
this.current++;
}
public DocumentMemento getMemento() {
if (this.current < 0) {
return null;
}
return this.mementos.get(this.current);
}
public DocumentMemento undo() {
if (this.current <= 0) {
return null;
}
this.current--;
return this.mementos.get(this.current);
}
public DocumentMemento redo() {
if (this.current >= this.mementos.size() - 1) {
return null;
}
this.current++;
return this.mementos.get(this.current);
}
}
// Client code
public class MementoPatternDemo {
public static void main(String[] args) {
Document document = new Document("Initial content");
DocumentHistory history = new DocumentHistory();
System.out.println(document);
history.addMemento(document.save());
document.setContent("First change");
System.out.println(document);
history.addMemento(document.save());
document.setContent("Second change");
System.out.println(document);
history.addMemento(document.save());
document.restore(history.undo().getContent());
System.out.println(document);
document.restore(history.undo().getContent());
System.out.println(document);
}
}
在这个例子中,Document 是发起人,它保存着文档的内容,DocumentMemento 是备忘录,用来存储文档的特定状态,DocumentHistory 是管理者,它负责保存和管理备忘录对象。通过这种方式,我们可以在任何时候保存文档的状态,并在需要时恢复到之前的状态。
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式有时也被称作发布/订阅模式或模型-视图模式。
核心组件
优点
缺点
适用场景
Java示例
以下是一个使用Java实现的观察者模式的简单示例,我们将创建一个天气预报系统,其中天气数据源(Subject)会通知多个天气显示设备(Observers):
import java.util.ArrayList;
import java.util.List;
// Observer interface
interface Observer {
void update(float temp, float humidity, float pressure);
}
// Subject interface
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// ConcreteSubject
class WeatherData implements Subject {
private List observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
// ConcreteObserver
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + " F degrees and " + humidity + "% humidity");
}
}
// Client code
public class ObserverPatternDemo {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
weatherData.registerObserver(currentDisplay);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
在这个例子中,WeatherData 是具体主题,它维护了一个观察者列表,并在状态改变时通知所有观察者。CurrentConditionsDisplay 是具体观察者,它实现了Observer接口,并在收到通知时更新自己的状态并显示出来。当WeatherData的状态改变时,所有注册的观察者都会被通知并更新自己的显示。
状态模式(State Pattern)是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。也就是说,对象看起来像是改变了其类。这个模式将与特定状态相关的行为封装在独立的类中,使得状态转换逻辑清晰且易于管理。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个简单的交通信号灯系统,它可以处于红灯、黄灯或绿灯三种状态之一,每种状态都有特定的行为:
// AbstractState
interface TrafficLightState {
void handle(TrafficLight light);
}
// ConcreteStates
class RedLightState implements TrafficLightState {
@Override
public void handle(TrafficLight light) {
System.out.println("Red Light: Stop");
light.setState(light.getYellowLightState());
}
}
class YellowLightState implements TrafficLightState {
@Override
public void handle(TrafficLight light) {
System.out.println("Yellow Light: Prepare to go");
light.setState(light.getGreenLightState());
}
}
class GreenLightState implements TrafficLightState {
@Override
public void handle(TrafficLight light) {
System.out.println("Green Light: Go");
light.setState(light.getRedLightState());
}
}
// Context
class TrafficLight {
private TrafficLightState state;
private TrafficLightState redLightState;
private TrafficLightState yellowLightState;
private TrafficLightState greenLightState;
public TrafficLight() {
redLightState = new RedLightState();
yellowLightState = new YellowLightState();
greenLightState = new GreenLightState();
state = redLightState; // Initial state
}
public void setState(TrafficLightState state) {
this.state = state;
}
public TrafficLightState getRedLightState() {
return redLightState;
}
public TrafficLightState getYellowLightState() {
return yellowLightState;
}
public TrafficLightState getGreenLightState() {
return greenLightState;
}
public void pressButton() {
state.handle(this);
}
}
// Client code
public class StatePatternDemo {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight();
for (int i = 0; i < 6; i++) {
trafficLight.pressButton();
}
}
}
在这个例子中,TrafficLight 是上下文,它维护了一个当前状态的引用。TrafficLightState 是抽象状态接口,定义了handle方法。RedLightState、YellowLightState 和 GreenLightState 是具体状态,它们实现了TrafficLightState接口,并在handle方法中定义了状态转换的逻辑。当TrafficLight的pressButton方法被调用时,它会调用当前状态的handle方法,从而改变自身的状态。
策略模式(Strategy Pattern)是一种行为设计模式,它使你能在运行时改变对象的行为。此模式定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。
核心组件
优点
缺点
适用场景
Java示例
假设我们正在开发一个游戏,游戏中有不同的敌人,每种敌人都有自己的攻击方式。我们可以使用策略模式来实现这一需求:
// Strategy Interface
interface AttackStrategy {
void attack();
}
// Concrete Strategies
class FireAttack implements AttackStrategy {
@Override
public void attack() {
System.out.println("Attacking with fire!");
}
}
class IceAttack implements AttackStrategy {
@Override
public void attack() {
System.out.println("Attacking with ice!");
}
}
// Context
class Enemy {
private AttackStrategy strategy;
public Enemy(AttackStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(AttackStrategy strategy) {
this.strategy = strategy;
}
public void performAttack() {
strategy.attack();
}
}
// Client Code
public class StrategyPatternDemo {
public static void main(String[] args) {
Enemy enemy = new Enemy(new FireAttack()); // Create an enemy with a fire attack strategy
enemy.performAttack(); // Perform the attack
enemy.setStrategy(new IceAttack()); // Change the strategy to ice attack
enemy.performAttack(); // Perform the new attack
}
}
在这个例子中:
AttackStrategy 是策略接口,定义了攻击行为。
FireAttack 和 IceAttack 是具体策略,实现了不同的攻击方式。
Enemy 是上下文,它持有一个策略对象,并通过performAttack方法委托给策略对象执行攻击行为。
通过策略模式,我们可以在运行时改变敌人的攻击方式,而无需修改Enemy类的代码。
模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
核心组件
优点
缺点
适用场景
Java示例
假设我们正在设计一个游戏,游戏中有多种类型的敌人,每种敌人的攻击方式大致相同,但具体实现有所不同。我们可以使用模板方法模式来实现这一需求:
// AbstractClass
abstract class Enemy {
// Template method
public final void attack() {
System.out.print("Enemy is preparing to attack...");
prepareAttack();
System.out.print("Enemy is performing the attack...");
performAttack();
System.out.println("Attack is over.");
}
// Basic operations
protected abstract void prepareAttack();
protected abstract void performAttack();
}
// ConcreteClass
class FireElemental extends Enemy {
@Override
protected void prepareAttack() {
System.out.print("Gathering fire energy...");
}
@Override
protected void performAttack() {
System.out.println("Flames burst out!");
}
}
class IceElemental extends Enemy {
@Override
protected void prepareAttack() {
System.out.print("Condensing ice particles...");
}
@Override
protected void performAttack() {
System.out.println("Ice shards shoot forward!");
}
}
// Client Code
public class TemplateMethodPatternDemo {
public static void main(String[] args) {
Enemy fireElemental = new FireElemental();
Enemy iceElemental = new IceElemental();
System.out.println("Fire Elemental attack:");
fireElemental.attack();
System.out.println("\nIce Elemental attack:");
iceElemental.attack();
}
}
在这个例子中:
Enemy 是抽象类,定义了attack模板方法和两个抽象的基本操作prepareAttack和performAttack。
FireElemental 和 IceElemental 是具体类,它们分别实现了prepareAttack和performAttack方法,提供了不同的攻击准备和执行方式。
通过模板方法模式,我们确保了所有敌人的攻击流程一致,同时允许每个敌人类型有其独特的攻击方式。
访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不改变类结构的情况下,向一组已经存在的类中添加新的行为。这种模式利用一个访问者类,该类的方法代表了作用于某种数据结构元素上的一些操作。
核心组件
优点
缺点
适用场景
Java示例
假设我们有一个表达式解析器,它可以解析加法和乘法表达式,我们可以使用访问者模式来实现:
// Element
interface Expression {
int interpret(Visitor visitor);
}
// ConcreteElements
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(Visitor visitor) {
return visitor.visitAddExpression(this);
}
}
class MultiplyExpression implements Expression {
private Expression left;
private Expression right;
public MultiplyExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Visitor visitor) {
return visitor.visitMultiplyExpression(this);
}
}
// Visitor
interface Visitor {
int visitAddExpression(AddExpression expression);
int visitMultiplyExpression(MultiplyExpression expression);
}
// ConcreteVisitor
class ExpressionEvaluator implements Visitor {
@Override
public int visitAddExpression(AddExpression expression) {
return expression.left.interpret(this) + expression.right.interpret(this);
}
@Override
public int visitMultiplyExpression(MultiplyExpression expression) {
return expression.left.interpret(this) * expression.right.interpret(this);
}
}
// Client Code
public class VisitorPatternDemo {
public static void main(String[] args) {
Expression expr1 = new AddExpression(new MultiplyExpression(new AddExpression(new AddExpression(new MultiplyExpression(null, null), null), null), null), null);
ExpressionEvaluator evaluator = new ExpressionEvaluator();
System.out.println("Result: " + expr1.interpret(evaluator));
}
}
在这个例子中:
Expression 接口是元素接口,它定义了一个interpret方法,用于接受访问者。
AddExpression 和 MultiplyExpression 是具体元素,它们实现了Expression接口,并在interpret方法中调用访问者的方法。
Visitor 接口定义了访问者,它包含了访问不同类型元素的方法。
ExpressionEvaluator 是具体访问者,它实现了Visitor接口,并提供了具体的访问逻辑。
通过访问者模式,我们可以轻松地添加新的操作,例如添加一个新的访问者类来计算表达式的导数,而无需修改现有的元素类。