23种设计模式

163 阅读18分钟

20230413095109.jpg

一、创建型

1、抽象工厂模式 Abstract Factory

抽象工厂模式也称为抽象工厂方法模式,是一种创建型设计模式,它提供了一个接口,用于创建一系列的相关或相互依赖的对象,而无需指定这些对象的具体类。抽象工厂模式的目的是为了让构建和实现分离,从而达到解耦的效果。

下面是一个Java示例代码,演示了如何使用抽象工厂模式创建不同操作系统下的对话框和按钮:

// 按钮接口
public interface Button {
    void paint();
}

// 对话框接口
public interface Dialog {
    Button createButton();
}

// Windows按钮实现类
public class WindowsButton implements Button {
    @Override
    public void paint() {
        System.out.println("Painting a windows button");
    }
}

// Windows对话框实现类
public class WindowsDialog implements Dialog {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
}

// MacOS按钮实现类
public class MacOSButton implements Button {
    @Override
    public void paint() {
        System.out.println("Painting a MacOS button");
    }
}

// MacOS对话框实现类
public class MacOSDialog implements Dialog {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }
}

// 操作系统抽象工厂
public interface GUIFactory {
    Dialog createDialog();
}

// Windows操作系统抽象工厂实现类
public class WindowsGUIFactory implements GUIFactory {
    @Override
    public Dialog createDialog() {
        return new WindowsDialog();
    }
}

// MacOS操作系统抽象工厂实现类
public class MacOSGUIFactory implements GUIFactory {
    @Override
    public Dialog createDialog() {
        return new MacOSDialog();
    }
}

在这个示例代码中,我们首先定义了一个Button接口和Dialog接口,分别表示按钮和对话框对象的接口。然后,我们实现了不同操作系统下的按钮和对话框的具体实现类WindowsButton、WindowsDialog、MacOSButton、MacOSDialog。

接着,我们定义了一个GUIFactory接口,它有一个createDialog()方法,用于创建对话框对象。然后,我们分别实现了不同操作系统下的GUIFactory工厂类WindowsGUIFactory和MacOSGUIFactory,它们分别实现了createDialog()方法,并创建了相应操作系统下的对话框和按钮对象。

通过这种方式,我们可以在客户端使用不同的工厂对象来创建不同操作系统下的对话框和按钮对象。例如:

GUIFactory factory1 = new WindowsGUIFactory();
Dialog dialog1 = factory1.createDialog();
Button button1 = dialog1.createButton();
button1.paint(); // Output: Painting a windows button

GUIFactory factory2 = new MacOSGUIFactory();
Dialog dialog2 = factory2.createDialog();
Button button2 = dialog2.createButton();
button2.paint(); // Output: Painting a MacOS button

在这个示例代码中,我们首先创建了一个WindowsGUIFactory对象factory1,然后调用它的createDialog()方法来创建一个WindowsDialog对象dialog1,再调用dialog1的createButton()方法来创建一个WindowsButton对象button1。最后,调用button1的paint()方法来绘制Windows按钮。

接着,我们又创建了一个MacOSGUIFactory对象factory2,调用它的createDialog()方法来创建一个MacOSDialog对象dialog2,并通过它的createButton()方法来创建一个MacOSButton对象button2。最后调用button2的paint()方法来绘制MacOS按钮。

通过抽象工厂模式,我们可以将对象的创建和使用分离开来,使得系统更加灵活和可扩展。同时,它也避免了具体产品类和客户端之间的紧耦合关系。

2、生成器模式 Builder

生成器模式也称为建造者模式,是一种创建型设计模式,用于将一个大的复杂对象的构建过程分解成多个小的、独立且可组合的部分。生成器模式主要解决了在创建复杂对象时,对象内部结构复杂,构造函数参数过多,且很多参数具有默认值的问题。

下面是一个Java示例代码,演示了如何使用生成器模式来创建一个汽车对象:

public class Car {
    private String brand;
    private String model;
    private int year;
    private String color;
    private String engine;

    public Car(String brand, String model, int year, String color, String engine) {
        this.brand = brand;
        this.model = model;
        this.year = year;
        this.color = color;
        this.engine = engine;
    }

    public String getBrand() {
        return brand;
    }

    public String getModel() {
        return model;
    }

    public int getYear() {
        return year;
    }

    public String getColor() {
        return color;
    }

    public String getEngine() {
        return engine;
    }
}

public interface CarBuilder {
    CarBuilder setBrand(String brand);
    CarBuilder setModel(String model);
    CarBuilder setYear(int year);
    CarBuilder setColor(String color);
    CarBuilder setEngine(String engine);
    Car build();
}

public class CarBuilderImpl implements CarBuilder {
    private String brand;
    private String model;
    private int year;
    private String color;
    private String engine;

    @Override
    public CarBuilder setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    @Override
    public CarBuilder setModel(String model) {
        this.model = model;
        return this;
    }

    @Override
    public CarBuilder setYear(int year) {
        this.year = year;
        return this;
    }

    @Override
    public CarBuilder setColor(String color) {
        this.color = color;
        return this;
    }

    @Override
    public CarBuilder setEngine(String engine) {
        this.engine = engine;
        return this;
    }

    @Override
    public Car build() {
        return new Car(brand, model, year, color, engine);
    }
}

在这个示例代码中,我们首先定义了一个Car类,它表示一个汽车对象。Car类的构造函数有5个参数,分别表示汽车品牌、型号、年份、颜色和发动机。

然后,我们定义了一个CarBuilder接口,它有5个用于设置汽车参数的方法和一个build()方法用于创建Car对象。实现CarBuilder接口的CarBuilderImpl类可以用于创建一个Car对象。

下面是一个使用生成器模式创建Car对象的示例代码:

Car car = new CarBuilderImpl()
                .setBrand("Ford")
                .setModel("Mustang")
                .setYear(2020)
                .setColor("red")
                .setEngine("5.0L V8")
                .build();

System.out.println(car.getBrand() + " " + car.getModel() + " " + car.getYear() + " " + car.getColor() + " " + car.getEngine());

在这个示例代码中,我们首先使用CarBuilderImpl类创建一个CarBuilder对象,然后连续调用它的setXXX()方法设置汽车的各个参数。最后,调用它的build()方法创建一个Car对象。我们可以通过这个Car对象的getXXX()方法来获取它的各个参数,并输出它们的值。

使用生成器模式可以让对象的创建过程更加灵活和可扩展,同时也可以避免构造函数参数过多的问题。

3、工厂方法模式 Factory Method

工厂方法模式也称为工厂模式,是一种创建型设计模式,它定义了一个用于创建对象的接口,但将具体的创建工作延迟到了子类中。这样,工厂方法模式可以让类在不修改原始代码的情况下,通过继承和多态性创建不同的对象。

下面是一个Java示例代码,演示了如何使用工厂方法模式创建不同的对象:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}

public interface ShapeFactory {
    Shape createShape();
}

public class CircleFactory implements ShapeFactory {
    @Override 
    public Circle createShape() {
        return new Circle();
    }
}

public class RectangleFactory implements ShapeFactory {
    @Override 
    public Rectangle createShape() {
        return new Rectangle();
    }
}

在这个示例代码中,我们定义了一个Shape接口,它有一个draw()方法。我们还实现了两个具体的实现类Circle和Rectangle,它们分别实现了draw()方法。

另外,我们定义了一个ShapeFactory接口,它有一个createShape()方法,用于创建Shape对象。然后,我们实现了两个具体的ShapeFactory工厂类CircleFactory和RectangleFactory,它们分别实现了createShape()方法,并分别创建了Circle和Rectangle对象。

通过这种方式,我们可以在客户端使用不同的工厂对象来创建不同的Shape对象。例如:

ShapeFactory factory1 = new CircleFactory();
Shape circle = factory1.createShape();
circle.draw(); // Output: Drawing a circle

ShapeFactory factory2 = new RectangleFactory();
Shape rectangle = factory2.createShape();
rectangle.draw(); // Output: Drawing a rectangle

在这个示例代码中,我们首先创建了一个CircleFactory对象factory1,然后调用它的createShape()方法来创建一个Circle对象circle,最后调用circle的draw()方法来绘制圆形。

接着,我们又创建了一个RectangleFactory对象factory2,调用它的createShape()方法来创建一个Rectangle对象rectangle,并调用rectangle的draw()方法来绘制矩形。

通过工厂方法模式,我们可以将对象的创建和使用分离开来,使得系统更加灵活和可扩展。

4、原型模式 Prototype

原型模式是一种创建型设计模式,它允许通过复制(克隆)现有对象来创建新对象,而无需从头开始编写代码来创建新对象。通常,原型模式的实现方式是在原型类中添加一个clone()方法,通过调用该方法来创建新对象。

下面是一个Java示例代码,演示了如何使用原型模式来创建新对象:

public class Rectangle implements Cloneable {
    private int width;
    private int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    @Override
    public Rectangle clone() throws CloneNotSupportedException {
        return (Rectangle) super.clone();
    }
}

在这个示例代码中,Rectangle类实现了Cloneable接口,并覆写了clone()方法。clone()方法会调用继承自Object类的clone()方法,该方法会返回一个浅克隆的对象。我们可以通过在子类中覆写clone()方法来实现深克隆。

下面是一个使用原型模式创建新对象的示例代码:

Rectangle rect1 = new Rectangle(100, 50);
Rectangle rect2 = rect1.clone();
rect2.setWidth(200);

System.out.println("rect1: " + rect1.getWidth() + ", " + rect1.getHeight()); // Output: rect1: 100, 50
System.out.println("rect2: " + rect2.getWidth() + ", " + rect2.getHeight()); // Output: rect2: 200, 50

在这个示例代码中,我们先创建了一个Rectangle对象rect1,并设置它的宽度为100,高度为50。然后,我们通过调用rect1的clone()方法,克隆出一个新的Rectangle对象rect2。由于是浅克隆,rect2的宽度和高度与rect1相同。接着,我们设置rect2的宽度为200,而留下rect1不变。最后输出rect1和rect2的宽度和高度。可以看到,rect1的宽度仍为100,而rect2的宽度变成了200,说明我们成功地通过原型模式创建了一个新的对象。

5、单例模式 Singleton

单例模式是一种创建型设计模式,它保证了一个类只有一个实例,并提供了全局访问该实例的方式。单例模式常被用于控制资源的分配,例如线程池、数据库连接池等。

下面是一个Java示例代码,演示了如何实现单例模式:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在这个示例代码中,Singleton类有一个私有的构造函数,确保不能通过外部创建多个实例。getInstance()方法是静态的,并且返回一个Singleton实例。如果实例还不存在,getInstance()方法会创建一个新的实例,否则直接返回现有实例。需要注意的是,为了线程安全,getInstance()方法是同步的。

二、结构型

1、适配器模式 Adapter

适配器模式(Adapter Pattern)是一种结构型模式,它将一种类的接口转换成另一种接口,从而让原本不兼容的类可以合作无间。适配器模式存在两种形式:类适配器模式和对象适配器模式。

类适配器模式使用多重继承来对一个接口与另一个接口进行适配,而对象适配器模式则使用对象的组合来实现这个目的。适配器模式中,适配器类扮演着中间连接器的角色,在两个不同接口间起到了连接的作用。

下面是一个示例Java代码:

interface MediaPlayer {
    void play(String audioType, String fileName);
}

interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

class VlcPlayer implements AdvancedMediaPlayer {

    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // do nothing
    }
}

class Mp4Player implements AdvancedMediaPlayer {

    @Override
    public void playVlc(String fileName) {
        // do nothing
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMediaPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer.playMp4(fileName);
        }
    }
}

class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file. Name: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
        }
    }
}

public class Client {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "beyond the horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far far away.vlc");
        audioPlayer.play("avi", "mind me.avi");
    }
}

在上面的代码中,我们使用了音频播放器来演示适配器模式。在这个例子中,MediaPlayer接口是原有的播放器接口,AdvancedMediaPlayer接口是新接口。我们创建了VlcPlayerMp4Player两个实现类来实现新接口AdvancedMediaPlayer。此外,我们创建了一个适配器(MediaAdapter),以便旧接口的实现类也可以调用新接口的方法。最后,我们创建了原始的AudioPlayer类。这个类通过判断文件类型,如果是mp3类型就调用原有的播放器播放,如果是其他类型的音频文件,则使用适配器(MediaAdapter)对象调用新接口AdvancedMediaPlayer的方法进行播放。这个过程体现了适配器模式的使用。

在客户端代码中,我们创建了一个AudioPlayer对象,然后用它来播放不同类型的音频文件。虽然我们只实现了mp3、vlc、mp4三种文件格式的播放,但是我们不需要修改现有的播放器类或适配器类,就可以很方便地添加更多的支持的文件格式,这体现了适配器模式的灵活性和可扩展性。

2、桥接模式 Bridge

桥接模式(Bridge Pattern)是一种结构型模式,它可以将抽象部分与实现部分分离,以便它们能够独立地变化。这种方式通过组合的方式实现,而不是通过继承实现。

桥接模式核心的两个概念是:抽象和实现。抽象指的是一种类型或者类,而实现指的是用于实现这个类型或类功能的协作类。在如此抽象和实现两个概念的普及范围内,两者之间有许多关系。通过桥接,可以将它们分离出来,从而使得它们可以独立地变化而对彼此无影响。

下面是一个示例Java代码:

// 实现部分接口
interface Color {
    void fillWithColor(int border);
}

class RedColor implements Color {

    @Override
    public void fillWithColor(int border) {
        System.out.println("Filling with red color with border size " + border);
    }
}

class GreenColor implements Color {

    @Override
    public void fillWithColor(int border) {
        System.out.println("Filling with green color with border size " + border);
    }
}

// 抽象部分类
abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    abstract void draw();

    abstract void modifyBorder(int border);
}

class Square extends Shape {

    public Square(Color color) {
        super(color);
    }

    @Override
    void draw() {
        System.out.println("Drawing square");
        color.fillWithColor(5);
    }

    @Override
    void modifyBorder(int border) {
        System.out.println("Modifying the square border!");
        color.fillWithColor(border);
    }
}

class Triangle extends Shape {

    public Triangle(Color color) {
        super(color);
    }

    @Override
    void draw() {
        System.out.println("Drawing triangle");
        color.fillWithColor(7);
    }

    @Override
    void modifyBorder(int border) {
        System.out.println("Modifying the triangle border!");
        color.fillWithColor(border);
    }
}

public class Client {
    public static void main(String[] args) {
        Shape greenTriangle = new Triangle(new GreenColor());
        Shape redSquare = new Square(new RedColor());

        greenTriangle.draw();
        greenTriangle.modifyBorder(1);

        redSquare.draw();
        redSquare.modifyBorder(3);
    }
}

在上面的代码中,有两个抽象的部分:ShapeColor。这两个抽象部分之间存在桥接关系,通过实现Shape中引用Color实现的细节,ShapeColor可以在各自的实现中独立变化。具体实现方案在代码中的TriangleSquareGreenColorRedColor类中体现出来。

在客户端代码中,我们创建一个绿色三角形和一个红色正方形,然后调用它们的drawmodifyBorder方法,展示了桥接模式的使用场景。

3、组合模式 Composite

组合模式(Composite Pattern)是一种结构型模式,它允许我们将对象组合成树形结构来表示”部分-整体“的层次结构,使得客户端能够以一致的方式处理单个对象和组合对象。组合模式基本上定义了两种类型的对象:一种是容器,它包含其他的对象,另一种是被包含的对象。这种结构可以递归地定义,形成一个树形结构,常常被用于树形菜单或者文件系统的设计。

下面是一个Java示例代码:

import java.util.ArrayList;
import java.util.List;

interface Graphic {
    void print();
}

class Circle implements Graphic {

    @Override
    public void print() {
        System.out.println("Print Circle.");
    }
}

class Rectangle implements Graphic {

    @Override
    public void print() {
        System.out.println("Print Rectangle.");
    }
}

class CompoundGraphic implements Graphic {
    private List<Graphic> childGraphics = new ArrayList<>();

    public void addGraphic(Graphic graphic) {
        childGraphics.add(graphic);
    }

    public void removeGraphic(Graphic graphic) {
        childGraphics.remove(graphic);
    }

    @Override
    public void print() {
        for (Graphic graphic : childGraphics) {
            graphic.print();
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Circle circle1 = new Circle();
        Circle circle2 = new Circle();
        Rectangle rectangle1 = new Rectangle();
        CompoundGraphic compoundGraphic1 = new CompoundGraphic();
        compoundGraphic1.addGraphic(circle1);
        compoundGraphic1.addGraphic(circle2);
        CompoundGraphic compoundGraphic2 = new CompoundGraphic();
        compoundGraphic2.addGraphic(rectangle1);
        CompoundGraphic compoundGraphic3 = new CompoundGraphic();
        compoundGraphic3.addGraphic(compoundGraphic1);
        compoundGraphic3.addGraphic(compoundGraphic2);
        compoundGraphic3.print();
    }
}

在上面的代码中,我们定义了三个类:CircleRectangleCompoundGraphic。圆和矩形分别是简单的绘图元素,而CompoundGraphic是一个可复合的图形元素,包含多个子元素。在CompoundGraphic类中,我们使用了一个List对象来储存子元素,并实现了addGraphicremoveGraphic方法用于添加和删除子元素。print方法用于遍历整个图形元素树,并打印出每个子元素的调用结果。

Client类中,我们定义了一个复杂的图形元素树,有两个圆和一个矩形组成的图形元素组成了一个复合图形元素,而这个复合图形元素又被另一个复合图形元素所包含。最终,在客户端调用组合对象的print方法时,会遍历整个图形元素树,依次打印出每个子元素的调用结果。

4、装饰器模式 Decorator

装饰器模式是一种结构型设计模式,允许您通过将对象放入包装器中来动态修改对象的行为。装饰器模式通过创建包装器对象来扩展另一个对象的功能,而不会修改其原始实现。动态地给一个对象添加一些额外的职责

下面是一个Java示例代码:

public interface Car {
    void assemble();
}

public class BasicCar implements Car {
    @Override
    public void assemble() {
        System.out.print("Basic car.");
    }
}

public abstract class CarDecorator implements Car {
    protected Car car;

    public CarDecorator(Car car) {
        this.car = car;
    }

    public void assemble() {
        this.car.assemble();
    }
}

public class SportsCar extends CarDecorator {
    public SportsCar(Car car) {
        super(car);
    }

    public void assemble() {
        super.assemble();
        System.out.print(" Adding Sport features.");
    }
}

public class LuxuryCar extends CarDecorator {
    public LuxuryCar(Car car) {
        super(car);
    }

    public void assemble() {
        super.assemble();
        System.out.print(" Adding Luxury features.");
    }
}

public class DecoratorPatternExample {
    public static void main(String[] args) {
        Car sportsCar = new SportsCar(new BasicCar());
        sportsCar.assemble();
        System.out.println("\n");

        Car luxurySportsCar = new LuxuryCar(new SportsCar(new BasicCar()));
        luxurySportsCar.assemble();
    }
}

在上面的示例中,我们定义了一个Car接口和一个BasicCar实现它。然后,我们创建了一个抽象的CarDecorator类,它封装了一个Car实例,并在其上定义了一个assemble()方法。接下来,我们创建了两个具体的装饰器类SportsCar和LuxuryCar,它们扩展了CarDecorator类,并实现了assemble()方法以添加了一些新功能。最后,我们在示例中创建一个SportsCar和一个LuxurySportsCar实例,并分别调用它们的assemble()方法来验证结果。

5、外观模式 Facade

外观模式(Facade Pattern)是一种结构型设计模式,它为复杂的子系统提供一个简化的接口,以使其更易于使用。相当于给系统中的一组接口提供一个高层接口,这样就简化了系统的使用和降低了耦合度。

以下是 Java 示例代码:

在这个示例中,我们将实现一个外观模式,它将封装三个子系统(邮件系统、短信系统、通知系统)并提供一个简化的接口(sendNotification),以便客户端使用。

// 邮件系统
class EmailSystem {
    public void sendEmail(String email, String message) {
        System.out.println("发送邮件至:" + email);
        System.out.println("消息内容:" + message);
    }
}

// 短信系统
class SMS {
    public void sendSMS(String phoneNumber, String message) {
        System.out.println("发送短信至:" + phoneNumber);
        System.out.println("消息内容:" + message);
    }
}

// 通知系统
class Notification {
    public void sendNotification(String receiver, String message) {
        System.out.println("发送通知至:" + receiver);
        System.out.println("消息内容:" + message);
    }
}

// 外观类
class NotificationFacade {
    private EmailSystem emailSystem;
    private SMS sms;
    private Notification notification;

    public NotificationFacade() {
        emailSystem = new EmailSystem();
        sms = new SMS();
        notification = new Notification();
    }

    public void sendNotification(String receiver, String message) {
        emailSystem.sendEmail(receiver, message);
        sms.sendSMS(receiver, message);
        notification.sendNotification(receiver, message);
    }
}

// 客户端
public class FacadePatternDemo {
    public static void main(String[] args) {
        NotificationFacade facade = new NotificationFacade();
        facade.sendNotification("张三", "您的邮件已经到达。");
    }
}

输出结果:

发送邮件至:张三
消息内容:您的邮件已经到达。
发送短信至:张三
消息内容:您的邮件已经到达。
发送通知至:张三
消息内容:您的邮件已经到达。

在这个示例中,我们将三个系统封装到一个外观类中,然后定义了一个简化的接口(sendNotification),用于向所有系统发送通知。在客户端中,我们只需要实例化外观类,并使用该接口发送通知即可。这样就大大简化了客户端的代码,并且使得系统易于维护和修改。

6、享元模式 Flyweight

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来减少内存使用和提高性能。它将对象分为两类:内部状态和外部状态。内部状态是不随环境变化而改变的状态,而外部状态是随环境变化而改变的状态。享元模式通过共享具有相同内部状态的对象,来减少内存的使用,并提高系统的性能。运用共享技术有效地支持大量细粒度的对象

以下是 Java 示例代码:

在这个示例中,我们将实现一个军队模拟器,以演示享元模式。将会创建一个Soldier类代表面向对象模型中的具体享元,以及一个SoldierFactory来创建和管理Soldier对象。Soldier对象包含内部状态(类型和武器)和外部状态(所属队伍和坐标)。

// Soldier类,代表具体享元
class Soldier {
    private String type;
    private String weapon;

    public Soldier(String type, String weapon) {
        this.type = type;
        this.weapon = weapon;
    }

    public void deploy(String team, int x, int y) {
        System.out.println(type + "士兵带着" + weapon + ",部署于" + team + "队,坐标(" + x + "," + y + ")");
    }
}

// Soldier工厂类,用于创建和管理Soldier对象
class SoldierFactory {
    private static Map<String, Soldier> soldierMap = new HashMap<>();

    public static Soldier getSoldier(String type, String weapon) {
        Soldier soldier = soldierMap.get(type);

        if (soldier == null) {
            soldier = new Soldier(type, weapon);
            soldierMap.put(type, soldier);
        }

        return soldier;
    }
}

// 客户端
public class FlyweightPatternDemo {
    // 坐标
    private static int[][] coordinates = {
            {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}
    };

    // 队伍
    private static String[] teams = {"blue", "green"};

    // 武器
    private static String[] weapons = {"AK47", "M16"};

    public static void main(String[] args) {
        // 部署所有士兵
        for (int i = 0; i < coordinates.length; i++) {
            Soldier soldier = SoldierFactory.getSoldier(getRandomType(), getRandomWeapon());
            soldier.deploy(getRandomTeam(), coordinates[i][0], coordinates[i][1]);
        }
    }

    // 生成随机类型
    private static String getRandomType() {
        return ["Rifleman", "Grenadier", "Sniper"][(int) (Math.random() * 3)];
    }

    // 生成随机武器
    private static String getRandomWeapon() {
        return weapons[(int) (Math.random() * weapons.length)];
    }

    // 生成随机队伍
    private static String getRandomTeam() {
        return teams[(int) (Math.random() * teams.length)];
    }
}

输出结果:

Rifleman士兵带着AK47,部署于green队,坐标(1,1)
Grenadier士兵带着M16,部署于green队,坐标(1,2)
Sniper士兵带着M16,部署于blue队,坐标(1,3)
Rifleman士兵带着AK47,部署于green队,坐标(2,1)
Grenadier士兵带着M16,部署于blue队,坐标(2,2)
Grenadier士兵带着M16,部署于blue队,坐标(2,3)

在这个示例中,我们使用SoldierFactory工厂类来管理Soldier对象。如果指定类型的Soldier已经存在,工厂就在内存池中查找该对象并返回;否则,它就创建一个新的对象,并将其添加到内存池中。通过共享具有相同内部状态的对象,我们将内存使用减少到最小,并提高了系统的性能。

7、代理模式 Proxy

代理模式是一种结构型设计模式,它以代理对象控制原始对象的访问,以达到控制访问的目的。代理模式通常用于在不直接访问某个对象的情况下控制对其的访问,或为原始对象提供有价值的补充操作。

Java示例代码:

// 接口
public interface Image {
    void display();
}

// 实现类
public class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(filename);
    }

    @Override
    public void display() {
        System.out.println("显示:" + filename);
    }

    private void loadFromDisk(String filename) {
        System.out.println("加载:" + filename);
    }
}

// 代理类
public 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 Client {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");

        // 第一次加载图片,会先输出“加载:test.jpg”
        image.display();

        // 第二次加载图片,不再输出“加载:test.jpg”
        image.display();
    }
}

在这个示例中,RealImage是实现了Image接口的原始对象,它负责实际的图片加载和显示。ProxyImageImage接口的代理类,它控制了对RealImage的访问,并在需要时创建RealImage。当第一次加载图片时,ProxyImage创建了一个RealImage对象并调用其display方法,输出“加载:test.jpg”和“显示:test.jpg”。当再次加载图片时,ProxyImage不再创建RealImage对象,直接调用其display方法,输出“显示:test.jpg”。

三、行为型

1、责任链模式 Chain of Responsibility

责任链模式是一种行为型设计模式,它将请求的发送者和接收者解耦,通过一条链来处理请求,并且链上的每个对象均有可能处理请求,直到其中某个对象处理为止。通常用于解耦多个处理对象,避免请求发送者和接收者之间的耦合。

Java示例代码:

// 抽象处理类
public abstract class Handler {
    protected Handler successor; // 后继者

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(int request);
}

// 具体处理类A
public class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 0 && request < 10) {
            System.out.println("处理请求:" + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 具体处理类B
public class ConcreteHandlerB extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            System.out.println("处理请求:" + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 具体处理类C
public class ConcreteHandlerC extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 20 && request < 30) {
            System.out.println("处理请求:" + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Handler h1 = new ConcreteHandlerA();
        Handler h2 = new ConcreteHandlerB();
        Handler h3 = new ConcreteHandlerC();
        h1.setSuccessor(h2);
        h2.setSuccessor(h3);

        int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};

        for (int request : requests) {
            h1.handleRequest(request);
        }
    }
}

在这个示例中,Handler类为抽象处理类,其中定义了一个后继者。如果当前处理者无法处理请求,则将请求传递给后继者处理。具体处理类ConcreteHandlerAConcreteHandlerBConcreteHandlerC分别实现了handleRequest方法,用于具体处理请求。在客户端中,将处理器按照先后顺序串联起来,并依次处理一系列请求。如果某个请求可以被当前处理器处理,则直接处理,否则传递给后继者处理。

责任链模式的优点在于它可以灵活地增加或改变处理器的顺序或结构,而不需要修改客户端代码,仅仅修改处理器类即可。同时责任链也保证了请求会被处理,避免了请求发送者和接收者之间的紧耦合。

2、命令模式 Command

命令模式(Command Pattern)是一种行为设计模式,它将请求转换为一个包含所有必要信息的独立对象,以此来解耦发送者和接收者。命令模式允许您将操作请求参数化,延迟它们的执行,将操作放入队列,或者支持撤消的操作

一个命令模式通常由四个角色组成:抽象命令(抽象类或接口)、具体命令类、调用者(Invoker)和接收者(Receiver)。

下面是一个简单的Java示例代码:

首先,我们定义一个抽象命令类(Command):

public interface Command {
    void execute();
}

接下来,我们创建两个具体命令类(LightOnCommand和LightOffCommand):

public class LightOnCommand implements Command {

    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}

public class LightOffCommand implements Command {

    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.off();
    }
}

这里的Light是一个实体,它有两个操作on和off。

接下来,我们创建一个调用者类(RemoteControl),它可以执行命令并有一个撤销命令的操作:

public class RemoteControl {

    private Command command;
    private Command undoCommand;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
        undoCommand = command;
    }

    public void undoCommand() {
        undoCommand.execute();
    }
}

最后,我们创建一个接收者类(Light):

public class Light {
    public void on() {
        System.out.println("Light is turned on");
    }

    public void off() {
        System.out.println("Light is turned off");
    }
}

现在,我们可以测试一下:

Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);

RemoteControl control = new RemoteControl();

// turn on the light
control.setCommand(lightOnCommand);
control.executeCommand();

// turn off the light
control.setCommand(lightOffCommand);
control.executeCommand();

// undo the last command (i.e. turn on the light)
control.undoCommand();

输出结果:

Light is turned on
Light is turned off
Light is turned on

以上就是命令模式的一个简单的Java示例代码,它可以实现对于请求的解耦,可以撤销操作,对于需要这些功能的场景可以使用命令模式来实现。

3、解释器模式 Interpreter

解释器模式(Interpreter Pattern)是一种行为设计模式,它定义了一种方式来解释语言语法或表达式。它可以用于解析复杂的文本、语言、表达式等,并且可以用于语言编译器中词法分析和语法分析阶段。

一个解释器模式通常由两个角色组成:抽象表达式(抽象类或接口)和具体表达式类。

下面是一个简单的Java示例代码:

首先,我们定义一个抽象表达式类(Expression):

public interface Expression {
    int interpret();
}

接下来,我们创建两个具体表达式类(AddExpression和SubtractExpression):

public class AddExpression implements Expression {

    private Expression leftExpression;
    private Expression rightExpression;

    public AddExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    @Override
    public int interpret() {
        return leftExpression.interpret() + rightExpression.interpret();
    }
}

public class SubtractExpression implements Expression {

    private Expression leftExpression;
    private Expression rightExpression;

    public SubtractExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    @Override
    public int interpret() {
        return leftExpression.interpret() - rightExpression.interpret();
    }
}

这里我们定义了两个表达式,AddExpression和SubtractExpression。

接下来,我们创建一个解释器类(ExpressionParser),它可以将一个字符串解析成一个表达式:

public class ExpressionParser {

    public Expression parse(String expression) {
        Stack<Expression> stack = new Stack<>();

        for (String token : expression.split(" ")) {
            if (isOperator(token)) {
                Expression rightExpression = stack.pop();
                Expression leftExpression = stack.pop();
                Expression operator = getOperator(token, leftExpression, rightExpression);
                stack.push(operator);
            } else {
                Expression operand = new NumberExpression(token);
                stack.push(operand);
            }
        }

        return stack.pop();
    }

    private boolean isOperator(String token) {
        return "+".equals(token) || "-".equals(token);
    }

    private Expression getOperator(String token, Expression left, Expression right) {
        if ("+".equals(token)) {
            return new AddExpression(left, right);
        } else if ("-".equals(token)) {
            return new SubtractExpression(left, right);
        }

        return null;
    }
}

这里我们通过堆栈(stack)的方式解析这个表达式,将每个元素作为是否为运算符的判断依据来执行相应操作。

最后,我们创建一个NumberExpression类,它是表达式类的一个具体实现:

public class NumberExpression implements Expression {

    private int number;

    public NumberExpression(String number) {
        this.number = Integer.parseInt(number);
    }

    @Override
    public int interpret() {
        return number;
    }
}

现在,我们可以测试一下:

ExpressionParser parser = new ExpressionParser();
Expression expression = parser.parse("5 3 9 - +");
int result = expression.interpret();
System.out.println("Result: " + result);

输出结果:

Result: 7

以上就是解释器模式的一个简单的Java示例代码,它可以用于解析复杂的文本、语言、表达式,并且可以扩展此模式以实现更复杂的解析逻辑。

4、迭代器模式 Iterator

迭代器模式是一种行为型设计模式,它允许你在不暴露对象内部表示的情况下遍历容器中的元素。在迭代器模式中,容器提供迭代器来遍历其元素,而客户端使用迭代器遍历这些元素。

下面是迭代器模式的一些常见角色:

  • 迭代器(Iterator):定义遍历容器中元素的接口
  • 具体迭代器(ConcreteIterator):实现遍历容器中元素的接口
  • 容器(Container):定义获取迭代器的接口
  • 具体容器(ConcreteContainer):实现获取迭代器的接口,并返回具体迭代器的实例

以下是Java实现迭代器模式的示例代码:

// 迭代器接口
public interface Iterator<T> {
    boolean hasNext();
    T next();
}

// 具体迭代器实现
public class ConcreteIterator<T> implements Iterator<T> {
    private List<T> itemList;
    private int currentIndex;

    public ConcreteIterator(List<T> itemList) {
        this.itemList = itemList;
        this.currentIndex = 0;
    }

    @Override
    public boolean hasNext() {
        return currentIndex < itemList.size();
    }

    @Override
    public T next() {
        T item = itemList.get(currentIndex);
        currentIndex++;
        return item;
    }
}

// 容器接口
public interface Container<T> {
    Iterator<T> createIterator();
}

// 具体容器实现
public class ConcreteContainer<T> implements Container<T> {
    private List<T> itemList;

    public ConcreteContainer(List<T> itemList) {
        this.itemList = itemList;
    }

    @Override
    public Iterator<T> createIterator() {
        return new ConcreteIterator<>(itemList);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        List<String> itemList = new ArrayList<>();
        itemList.add("A");
        itemList.add("B");
        itemList.add("C");
        Container<String> container = new ConcreteContainer<>(itemList);
        Iterator<String> iterator = container.createIterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(item);
        }
    }
}

以上示例代码中,迭代器接口为Iterator,具体迭代器实现为ConcreteIterator。容器接口为Container,具体容器实现为ConcreteContainer。客户端代码使用具体容器实现来创建迭代器对象,并通过迭代器遍历容器中的元素。

5、中介者模式 Mediator

中介者模式是一种行为型设计模式,它允许多个对象之间相互通信而不需要相互依赖。它将对象之间的交互转移到一个中介者对象中,从而促进了对象之间的松耦合

中介者模式有一个中心对象,它负责协调对象的交互,具体来说,中介者对象负责处理对象的行为请求和控制对象之间的通信,让对象之间的协作更加简单有效。

下面是一个简单的Java示例代码,展示了中介者模式的实现。在这个示例中,我们有三个类:Colleague(同事类),ConcreteColleague1和ConcreteColleague2(具体同事类),和Mediator(中介者类)。

// Colleague.java
public abstract class Colleague {
    protected Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void send(String message);
    public abstract void receive(String message);
}

// ConcreteColleague1.java
public class ConcreteColleague1 extends Colleague {
    public ConcreteColleague1(Mediator mediator) {
        super(mediator);
    }

    public void send(String message) {
        mediator.send(message, this);
    }

    public void receive(String message) {
        System.out.println("ConcreteColleague1 received message: " + message);
    }
}

// ConcreteColleague2.java
public class ConcreteColleague2 extends Colleague {
    public ConcreteColleague2(Mediator mediator) {
        super(mediator);
    }

    public void send(String message) {
        mediator.send(message, this);
    }

    public void receive(String message) {
        System.out.println("ConcreteColleague2 received message: " + message);
    }
}

// Mediator.java
public interface Mediator {
    void send(String message, Colleague colleague);
}

// ConcreteMediator.java
public class ConcreteMediator implements Mediator {
    private ConcreteColleague1 colleague1;
    private ConcreteColleague2 colleague2;

    public void setColleague1(ConcreteColleague1 colleague1) {
        this.colleague1 = colleague1;
    }

    public void setColleague2(ConcreteColleague2 colleague2) {
        this.colleague2 = colleague2;
    }

    public void send(String message, Colleague colleague) {
        if (colleague == colleague1) {
            colleague2.receive(message);
        } else {
            colleague1.receive(message);
        }
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
        ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);

        mediator.setColleague1(colleague1);
        mediator.setColleague2(colleague2);

        colleague1.send("Hello, colleague2!");
        colleague2.send("Hi, colleague1!");
    }
}

在这个示例中,我们创建了两个具体同事类:ConcreteColleague1和ConcreteColleague2。这些同事类都继承自抽象同事类Colleague,并实现send和receive方法。

我们还创建了中介者ConcreteMediator。ConcreteMediator实现了Mediator接口,实现send方法。这个send方法决定了交换消息的具体逻辑。

在Client中,我们创建了ConcreteMediator、ConcreteColleague1和ConcreteColleague2的实例,并将它们传递给中介者。当同事类发送消息时,中介者决定了消息的交换方式。

总之,中介者模式能够将对象之间的交互进行解耦,并促进了对象之间的松耦合。

6、备忘录模式 Memento

备忘录模式是一种行为型设计模式,它可以在不破坏封装性的情况下捕捉并存储一个对象的内部状态,并在需要的时候将其恢复

备忘录模式包含三个主要角色:发起者(Originator)、备忘录(Memento)和管理者(Caretaker)。发起者是需要保存状态的对象,备忘录是存储对象状态的载体,管理者负责管理备忘录。

下面是一个简单的Java示例代码,展示了备忘录模式的实现。在这个示例中,我们有三个类:Memento、Originator和Caretaker。

// Memento.java
public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// Originator.java
public class Originator {
    private String state;

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(Memento memento) {
        state = memento.getState();
    }
}

// Caretaker.java
public class Caretaker {
    private Memento memento;

    public void saveState(Originator originator) {
        memento = originator.createMemento();
    }

    public void restoreState(Originator originator) {
        originator.restoreMemento(memento);
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State 1");
        System.out.println("Before save: " + originator.getState());

        caretaker.saveState(originator);

        originator.setState("State 2");
        System.out.println("After change: " + originator.getState());

        caretaker.restoreState(originator);
        System.out.println("After restore: " + originator.getState());
    }
}

在这个示例中,我们创建了Memento、Originator和Caretaker三个类。Originator是需要保存状态的对象,它拥有一个状态属性state,以及创建和恢复备忘录的方法createMemento和restoreMemento。Memento是存储Originator状态的类,包含一个保存状态的方法getState。Caretaker负责管理备忘录,它保存一个Memento对象,以及保存和恢复Memento对象的方法。

在Client中,我们首先创建了Originator和Caretaker的实例,然后设置Originator的状态为"State 1"。接着,我们打印出设置状态之前的状态,并调用caretaker.saveState保存Originator的状态。然后,我们改变Originator的状态为"State 2",并打印出这个状态。最后,我们使用caretaker.restoreState方法恢复Originator的状态,并打印出恢复状态之后的状态。

总之,备忘录模式可以将一个对象的状态进行保存和恢复,从而可以通过备忘录对象实现对象的快照操作。

7、观察者模式 Observer

观察者模式是一种行为型设计模式,它让一个对象(称为主题)来管理一组依赖于它的对象(称为观察者),并在它本身的状态改变时通知它们。

观察者模式包含两个主要角色:Subject(主题)和Observer(观察者)。当主题发生变化时,它会通知注册在它上面的所有观察者,以便它们可以更新自己。

下面是一个简单的Java示例代码,展示了观察者模式的实现。在这个示例中,我们有两个类:Subject(主题类)和Observer(观察者类)。

// Subject.java
import java.util.ArrayList;
import java.util.List;

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void detach(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

// Observer.java
public class Observer {
    private Subject subject;

    public Observer(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    public void update() {
        System.out.println("Observer received notification: " + subject.getState());
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        Subject subject = new Subject();

        Observer observer1 = new Observer(subject);
        Observer observer2 = new Observer(subject);

        subject.setState(10);

        subject.detach(observer2);
        subject.setState(20);
    }
}

在这个示例中,我们创建了Subject和Observer两个类。Subject保存了主题对象的状态,以及观察者对象的列表。它还定义了attach、detach和notifyObservers方法,用于添加和移除观察者,并通知观察者主题对象的状态发生改变。Observer类保存了主题对象的引用,并在构造函数中将自己添加到主题对象的观察者列表中。它还实现了update方法,以便在接收到主题对象状态改变的通知时进行处理。

在Client中,我们首先创建了Subject的实例,并创建了两个Observer的实例。然后,我们改变Subject对象的状态,并打印出接收到通知的Observer的状态。接着,我们从Subject对象中删除observer2对象,并再次改变其状态,并打印出接收通知的Observer的状态。

总之,观察者模式可以将主题对象与观察者对象解耦,从而让这两个对象可以独立地变化。这个模式提供了一种一对多的依赖关系,其中当主题对象的状态发生变化时,所有观察者都会接收到通知并进行相应的操作。

8、状态模式 State

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态改变时改变它的行为。在状态模式中,对象的类将其状态封装到不同的状态类中,从而使得对象在状态改变时可以动态的改变行为。状态模式提供了一种更好的方法来处理对象的状态变化,避免出现大量的if-else判断语句。

Java示例代码如下:

定义状态接口:

public interface State {
    void doAction(Context context);
}

定义状态具体实现类:

public class StateA implements State {
    public void doAction(Context context) {
        System.out.println("State A");
        context.setState(new StateB());
    }
}

public class StateB implements State {
    public void doAction(Context context) {
        System.out.println("State B");
        context.setState(new StateC());
    }
}

public class StateC implements State {
    public void doAction(Context context) {
        System.out.println("State C");
        context.setState(new StateA());
    }
}

定义具有状态的对象:

public class Context {
    private State state;
 
    public Context(){
       state = new StateA();
    }
 
    public void setState(State state){
       this.state = state;    
    }
 
    public State getState(){
       return state;
    }
 
    public void doAction(){
       state.doAction(this);
    }
}

测试代码:

public class Test {
    public static void main(String[] args) {
        Context context = new Context();
        context.doAction();
        context.doAction();
        context.doAction();
    }
}

输出:

State A
State B
State C

在上述示例中,状态模式将状态的转换和动作处理分离开来,客户端调用具有动作的对象,而具体的状态变换是由具体的状态类来完成的。这样可以保证对象的行为和状态相互独立,避免出现大量的复杂if-else判断语句,从而使得客户端和具体状态实现类之间的耦合度降低,提高了代码的可维护性和可扩展性。

9、策略模式 Strategy

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,以使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户

Java示例代码如下:

定义策略接口:

public interface Strategy {
    int doOperation(int num1, int num2);
}

定义策略实现类:

public class OperationAdd implements Strategy{
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}

public class OperationSubtract implements Strategy{
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}

public class OperationMultiply implements Strategy{
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}

定义Context类,根据传入的策略对象调用不同的策略方法:

public class Context {
   private Strategy strategy;
 
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
 
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

测试代码:

public class Test {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());    
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationSubtract());      
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationMultiply());    
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

输出:

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

在上述示例中,策略模式将算法和客户端解耦,客户端不用知道具体使用哪种算法,只需要知道调用的是Context类的executeStrategy方法,具体算法的实现是通过策略接口和具体策略类来完成的。这样可以方便的增加新的算法实现,同时也可以修改算法的实现,而不影响客户端的使用。

10、模版方法模式 Template Method

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架,将某些步骤延迟到子类中实现,使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤

Java示例代码如下:

定义抽象父类,其中包含模板方法和抽象方法:

public abstract class Game {
   protected abstract void initialize();
   protected abstract void startPlay();
   protected abstract void endPlay();

   // 模板方法
   public final void play(){     
      // 初始化游戏
      initialize();
     
      // 开始游戏
      startPlay();

      // 结束游戏
      endPlay();
   }
}

定义具体子类,继承父类并实现其抽象方法:

public class Cricket extends Game {

   @Override
   protected void endPlay() {
      System.out.println("Cricket Game Finished!");
   }

   @Override
   protected void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }

   @Override
   protected void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}

public class Football extends Game {

   @Override
   protected void endPlay() {
      System.out.println("Football Game Finished!");
   }

   @Override
   protected void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }

   @Override
   protected void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

测试代码:

public class Test {
   public static void main(String[] args) {

      Game game = new Cricket();
      game.play();

      System.out.println();

      game = new Football();
      game.play();      
   }
}

输出:

Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!

Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!

在上述示例中,模板方法模式通过定义一个算法的骨架并将某些步骤延迟到子类中实现,使得子类可以灵活的实现特定的算法步骤。父类中的模板方法控制了子类的执行流程,而具体的实现是由子类来完成的。由于算法的骨架是唯一的,因此算法的多样性是由子类来体现的。这样可以使得代码的重用性和可扩展性得到提高。

11、访问者模式 Visitor

访问者模式(Visitor Pattern)是一种行为型设计模式,它封装了一些作用于某种数据结构中的各元素的操作,可以将相关操作分离出来封装成独立的访问者类,从而达到数据结构与算法的解耦。

Java示例代码如下:

定义元素接口,其中包含accept方法用于接受访问者访问:

public interface Element {
    void accept(Visitor visitor);
}

定义具体元素类,实现元素接口:

public class Product implements Element {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

定义访问者接口,其中包含visit方法用于对元素进行访问:

public interface Visitor {
    void visit(Product product);
}

定义具体访问者类,实现访问者接口:

public class PriceVisitor implements Visitor {
    private double sum = 0;

    public void visit(Product product) {
        sum += product.getPrice();
    }

    public double getTotalPrice() {
        return sum;
    }
}

定义对象结构类,用于管理元素集合:

import java.util.ArrayList;
import java.util.List;

public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void attach(Element element) {
        elements.add(element);
    }

    public void detach(Element element) {
        elements.remove(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

测试代码:

public class Test {
    public static void main(String[] args) {
        ObjectStructure objects = new ObjectStructure();
        objects.attach(new Product("A", 10));
        objects.attach(new Product("B", 20));
        objects.attach(new Product("C", 30));

        PriceVisitor priceVisitor = new PriceVisitor();
        objects.accept(priceVisitor);
        System.out.println("Total price: " + priceVisitor.getTotalPrice());
    }
}

输出:

Total price: 60.0

在上述示例中,访问者模式将数据结构与算法进行了解耦。元素接口定义了accept方法,用于接受访问者的访问;访问者接口定义了visit方法,用于访问元素并执行相关操作。通过对象结构类将元素集合进行管理,访问者类只需定义相关操作,可以方便地对元素进行遍历和操作。这种模式可以方便的添加新的元素和访问者,同时也可以使代码更加易于维护和扩展。