Java 设计模式详解

引言

在软件开发中,设计模式提供了一套经过验证的解决方案,用于处理常见的设计问题。Java,作为一种面向对象编程语言,非常适合实现这些设计模式。设计模式不仅帮助提高代码的可读性和可维护性,还能增强代码的复用性和灵活性。本文将全面探讨 Java 中常见的设计模式,分为创建型、结构型和行为型三类,结合具体的 Java 代码示例进行讲解,希望能帮助读者在实际开发中有效应用这些设计模式。

创建型模式

创建型模式关注对象的创建过程,提供创建对象的机制,隐藏了创建逻辑,增强了代码的灵活性。

1. 单例模式(Singleton Pattern)

定义:确保一个类只有一个实例,并提供一个全局的访问点。

使用场景

  • 数据库连接池
  • 配置文件管理
  • 打印机或其他共享资源管理

优点

  • 控制资源访问
  • 减少内存开销

缺点

  • 由于单例模式的全局访问性,容易违反单一职责原则
  • 测试难度增加

实现方式

  • 懒汉式(线程不安全):
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 饿汉式(线程安全,但可能造成资源浪费):
public class Singleton {
    private static final Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}
  • 双重检查锁定(DCL)(线程安全且懒加载):
public class Singleton {
    private volatile static 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 doSomething() {
        // 单例的操作
    }
}
2. 工厂方法模式(Factory Method Pattern)

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

使用场景

  • 当一个类不知道它所必须创建的对象的类时
  • 需要将创建对象的过程延迟到子类时

优点

  • 符合开闭原则,扩展性好
  • 解耦创建和使用对象的代码

缺点

  • 增加了系统的复杂性和类数量

实现方式

// 抽象产品
interface Shape {
    void draw();
}

// 具体产品
class Circle implements Shape {
    public void draw() {
        System.out.println("Inside Circle::draw() method.");
    }
}

class Rectangle implements Shape {
    public void draw() {
        System.out.println("Inside Rectangle::draw() method.");
    }
}

// 抽象工厂
abstract class ShapeFactory {
    abstract Shape factoryMethod();
}

// 具体工厂
class CircleFactory extends ShapeFactory {
    Shape factoryMethod() {
        return new Circle();
    }
}

class RectangleFactory extends ShapeFactory {
    Shape factoryMethod() {
        return new Rectangle();
    }
}

// 使用
public class FactoryPatternDemo {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape shape1 = circleFactory.factoryMethod();
        shape1.draw();
        
        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape shape2 = rectangleFactory.factoryMethod();
        shape2.draw();
    }
}
3. 抽象工厂模式(Abstract Factory Pattern)

定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

使用场景

  • 需要一个系统独立于其产品的创建、组合和表示时
  • 系统需要使用多个产品系列,且要确保这些产品系列的使用一致性

优点

  • 更好的隔离具体类的实现
  • 符合开闭原则

缺点

  • 增加了系统的抽象性和理解难度

实现方式

// 抽象产品A
interface Color {
    void fill();
}

// 具体产品A
class Red implements Color {
    public void fill() {
        System.out.println("Red::fill()");
    }
}

class Green implements Color {
    public void fill() {
        System.out.println("Green::fill()");
    }
}

// 抽象产品B
interface Shape {
    void draw();
}

// 具体产品B
class Circle implements Shape {
    public void draw() {
        System.out.println("Circle::draw()");
    }
}

class Square implements Shape {
    public void draw() {
        System.out.println("Square::draw()");
    }
}

// 抽象工厂
interface AbstractFactory {
    Color getColor(String color);
    Shape getShape(String shape);
}

// 具体工厂1
class ShapeFactory implements AbstractFactory {
    public Color getColor(String color) {
        return null;
    }
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }        
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("SQUARE")) {
            return new Square();
        }
        return null;
    }
}

// 具体工厂2
class ColorFactory implements AbstractFactory {
    public Color getColor(String color) {
        if (color == null) {
            return null;
        }
        if (color.equalsIgnoreCase("RED")) {
            return new Red();
        } else if (color.equalsIgnoreCase("GREEN")) {
            return new Green();
        }
        return null;
    }
    public Shape getShape(String shape) {
        return null;
    }
}

// 工厂生产者
class FactoryProducer {
    public static AbstractFactory getFactory(String choice) {
        if (choice.equalsIgnoreCase("SHAPE")) {
            return new ShapeFactory();
        } else if (choice.equalsIgnoreCase("COLOR")) {
            return new ColorFactory();
        }
        return null;
    }
}

// 使用
public class AbstractFactoryPatternDemo {
    public static void main(String[] args) {
        //获取形状工厂
        AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
        Shape shape1 = shapeFactory.getShape("CIRCLE");
        shape1.draw();
        
        //获取颜色工厂
        AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
        Color color1 = colorFactory.getColor("RED");
        color1.fill();
    }
}
4. 建造者模式(Builder Pattern)

定义:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

使用场景

  • 需要创建的对象内部结构复杂
  • 需要对创建过程进行精细控制

优点

  • 可以很好地控制对象创建过程的细节
  • 符合单一职责原则

缺点

  • 增加了系统的复杂性

实现方式

// 产品
class Computer {
    private String HDD;
    private String RAM;

    public void setHDD(String HDD) {
        this.HDD = HDD;
    }

    public void setRAM(String RAM) {
        this.RAM = RAM;
    }

    @Override
    public String toString() {
        return "HDD: " + this.HDD + ", RAM: " + this.RAM;
    }
}

// 抽象建造者
abstract class ComputerBuilder {
    protected Computer computer;

    public Computer getComputer() {
        return computer;
    }

    public void createNewComputer() {
        this.computer = new Computer();
    }

    public abstract void buildHDD();
    public abstract void buildRAM();
}

// 具体建造者
class DellComputerBuilder extends ComputerBuilder {
    @Override
    public void buildHDD() {
        computer.setHDD("DELL HDD");
    }

    @Override
    public void buildRAM() {
        computer.setRAM("DELL RAM");
    }
}

class HPComputerBuilder extends ComputerBuilder {
    @Override
    public void buildHDD() {
        computer.setHDD("HP HDD");
    }

    @Override
    public void buildRAM() {
        computer.setRAM("HP RAM");
    }
}

// 指挥者
class ComputerDirector {
    public void constructComputer(ComputerBuilder builder) {
        builder.createNewComputer();
        builder.buildHDD();
        builder.buildRAM();
    }
}

// 使用
public class BuilderPatternDemo {
    public static void main(String[] args) {
        ComputerBuilder dellBuilder = new DellComputerBuilder();
        ComputerDirector director = new ComputerDirector();
        
        director.constructComputer(dellBuilder);
        Computer dellComputer = dellBuilder.getComputer();
        System.out.println("Dell Computer Config: " + dellComputer);
        
        ComputerBuilder hpBuilder = new HPComputerBuilder();
        director.constructComputer(hpBuilder);
        Computer hpComputer = hpBuilder.getComputer();
        System.out.println("HP Computer Config: " + hpComputer);
    }
}
5. 原型模式(Prototype Pattern)

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

使用场景

  • 当创建新实例成本较高时
  • 需要动态加载类时

优点

  • 性能提升,尤其是在创建复杂对象时
  • 避免构造函数的复杂性

缺点

  • 深拷贝和浅拷贝需要特别注意,可能会导致一些问题

实现方式

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

// 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型
class Employee implements Prototype {
    private List<String> projects;

    public Employee() {
        this.projects = new ArrayList<>();
    }

    public void loadData() {
        // 模拟从数据库加载数据
        projects.add("Project 1");
        projects.add("Project 2");
    }

    @Override
    public Prototype clone() {
        try {
            Employee clone = (Employee) super.clone();
            // 深拷贝
            clone.projects = new ArrayList<>(this.projects);
            return clone;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }

    public List<String> getProjects() {
        return projects;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "projects=" + projects +
                '}';
    }
}

// 使用
public class PrototypePatternDemo {
    public static void main(String[] args) {
        Employee employee = new Employee();
        employee.loadData();

        Employee clonedEmployee = (Employee) employee.clone();
        System.out.println("Original: " + employee.toString());
        System.out.println("Clone: " + clonedEmployee.toString());

        // 修改克隆对象,看是否影响到原对象
        clonedEmployee.getProjects().add("New Project");
        System.out.println("After adding new project to clone:");
        System.out.println("Original: " + employee.toString());
        System.out.println("Clone: " + clonedEmployee.toString());
    }
}
结构型模式

结构型模式关注类和对象的组合,旨在通过改变结构来实现新功能或简化现有结构。

1. 适配器模式(Adapter Pattern)

定义:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

使用场景

  • 需要使用一个已存在的类,而它的接口不符合我们的需求
  • 希望创建一个可以复用的类,该类可以与其他不相关或不可预见的类协同工作

优点

  • 让那些因接口不兼容而不能一起工作的类可以协同工作
  • 增加了类的透明性和复用性

缺点

  • 过多的使用适配器会让系统变得复杂

实现方式

// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 需要适配的接口
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 具体实现类
class VlcPlayer implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

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

class Mp4Player implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        // do nothing
    }

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

// 适配器
class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

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

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

// 客户端
class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;

    public void play(String audioType, String fileName) {
        // 内置支持mp3播放
        if(audioType.equalsIgnoreCase("mp3")){
            System.out.println("Playing mp3 file. Name: " + fileName);
        }
        // mediaAdapter提供了播放其他文件格式的支持
        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 AdapterPatternDemo {
    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");
    }
}
2. 桥接模式(Bridge Pattern)

定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

使用场景

  • 一个类存在两个独立变化的维度,且这两维度都需要扩展
  • 不希望使用子类来实现多维度的扩展

优点

  • 分离接口及其实现部分
  • 提高了系统的可扩展性

缺点

  • 增加了系统的理解和设计难度

实现方式

// 实现接口
interface DrawAPI {
    void drawCircle(int radius, int x, int y);
}

// 具体实现
class RedCircle implements DrawAPI {
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", y: " + y + "]");
    }
}

class GreenCircle implements DrawAPI {
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: green, radius: " + radius + ", x: " + x + ", y: " + y + "]");
    }
}

// 抽象类
abstract class Shape {
    protected DrawAPI drawAPI;
    
    protected Shape(DrawAPI drawAPI){
        this.drawAPI = drawAPI;
    }
    public abstract void draw();    
}

// 具体类
class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;  
        this.y = y;  
        this.radius = radius;
    }

    public void draw() {
        drawAPI.drawCircle(radius, x, y);
    }
}

// 使用
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape redCircle = new Circle(100, 100, 10, new RedCircle());
        Shape greenCircle = new Circle(100, 100, 10, new GreenCircle());

        redCircle.draw();
        greenCircle.draw();
    }
}
3. 组合模式(Composite Pattern)

定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

使用场景

  • 表示对象的部分-整体层次结构
  • 当你希望客户端可以一致地处理单个对象以及组合对象时

优点

  • 容易增加新类型的组件
  • 客户端代码可以简化,对复杂结构的操作变得一致

缺点

  • 可能导致设计变得过于通用,管理复杂性增加

实现方式

// 组件接口
interface Component {
    void operation();
}
// 叶子节点
class Leaf implements Component {
    private String name;
    public Leaf(String name) {
        this.name = name;
    }
    public void operation() {
        System.out.println("Leaf " + name + " operation");
    }
}
// 复合对象
class Composite implements Component {
    private List<Component> children = new ArrayList<>();
    private String name;
    public Composite(String name) {
        this.name = name;
    }
    public void add(Component component) {
        children.add(component);
    }
    public void remove(Component component) {
        children.remove(component);
    }
    public void operation() {
        System.out.println("Composite " + name + " operation");
        for (Component child : children) {
            child.operation();
        }
    }
}

// 使用
public class CompositePatternDemo {
    public static void main(String[] args) {
        Composite root = new Composite("root");
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));

        Composite comp = new Composite("Composite X");
        comp.add(new Leaf("Leaf XA"));
        comp.add(new Leaf("Leaf XB"));

        root.add(comp);
        root.add(new Leaf("Leaf C"));

        // 执行操作
        root.operation();
    }
}

这段代码中,Composite 类可以包含 Leaf 或其他 Composite,这就形成了一个树状结构。用户可以通过 operation 方法统一操作所有组件。

4. 装饰者模式(Decorator Pattern)

定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比生成子类更为灵活。

使用场景

  • 需要动态地、透明地给对象添加职责
  • 需要扩展功能,且子类化不切实际时

优点

  • 比继承更灵活,可以在运行时添加和删除责任
  • 符合开闭原则

缺点

  • 多层装饰会增加系统的复杂性

实现方式

// 组件接口
interface Shape {
    void draw();
}

// 具体组件
class Circle implements Shape {
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

// 抽象装饰者
abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }

    public void draw() {
        decoratedShape.draw();
    }
}

// 具体装饰者
class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }
}

// 使用
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Shape circle = new Circle();
        
        // 装饰形状
        Shape redCircle = new RedShapeDecorator(new Circle());
        
        System.out.println("Circle with normal border");
        circle.draw();
        
        System.out.println("\nCircle of red border");
        redCircle.draw();
    }
}
5. 外观模式(Facade Pattern)

定义:为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。

使用场景

  • 提供一个简化的接口来访问子系统的一个复杂部分
  • 需要构建层次结构的子系统时

优点

  • 减少系统的复杂性,提高了模块间的独立性
  • 符合迪米特法则(最少知识原则)

缺点

  • 不符合开闭原则,对新系统模块的变化可能需要修改外观类

实现方式

// 子系统1
class SubSystem1 {
    public void method1() {
        System.out.println("SubSystem1 Method1");
    }
}

// 子系统2
class SubSystem2 {
    public void method2() {
        System.out.println("SubSystem2 Method2");
    }
}

// 外观类
class Facade {
    private SubSystem1 sub1 = new SubSystem1();
    private SubSystem2 sub2 = new SubSystem2();

    public void methodA() {
        sub1.method1();
        sub2.method2();
    }
}

// 使用
public class FacadePatternDemo {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.methodA();
    }
}
6. 享元模式(Flyweight Pattern)

定义:运用共享技术有效地支持大量细粒度的对象。

使用场景

  • 程序中使用了大量相似对象,导致内存占用过大时
  • 对象的大部分状态可以外部化时

优点

  • 减少内存使用,提高性能

缺点

  • 需要额外管理共享对象,增加复杂性
  • 可能导致线程安全问题,需要额外处理

实现方式

// 享元接口
interface Shape {
    void draw();
}

// 具体享元
class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public void draw() {
        System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
}

// 享元工厂
class ShapeFactory {
    private static HashMap<String, Shape> circleMap = new HashMap<>();

    public static Shape getCircle(String color) {
        Circle circle = (Circle)circleMap.get(color);

        if(circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("Creating circle of color : " + color);
        }
        return circle;
    }
}

// 使用
public class FlyweightPatternDemo {
    private static final int COLORS_COUNT = 10;

    public static void main(String[] args) {
        for(int i=0; i < COLORS_COUNT; i++) {
            Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor());
            circle.setX(getRandomX());
            circle.setY(getRandomY());
            circle.setRadius(100);
            circle.draw();
        }
    }

    private static String getRandomColor() {
        return Color.values()[new Random().nextInt(Color.values().length)].toString();
    }

    private static int getRandomX() {
        return new Random().nextInt(100);
    }

    private static int getRandomY() {
        return new Random().nextInt(100);
    }

    enum Color {
        RED, GREEN, BLUE, YELLOW, BLACK
    }
}
7. 代理模式(Proxy Pattern)

定义:为其他对象提供一种代理以控制对这个对象的访问。

使用场景

  • 需要在访问对象时执行一些额外的操作(如日志记录、权限检查)
  • 需要延迟对象的初始化时(懒加载)

优点

  • 能够控制对原对象的访问
  • 可以实现额外的功能,如安全控制、日志、性能监控

缺点

  • 增加了系统的复杂性

实现方式

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

// 真实对象
class RealImage implements Image {
    private String fileName;

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

    private void loadFromDisk(String fileName) {
        System.out.println("Loading " + fileName);
    }

    public void display() {
        System.out.println("Displaying " + fileName);
    }
}

// 代理对象
class ProxyImage implements Image {
    private RealImage realImage;
    private String fileName;

    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }

    public void display() {
        if(realImage == null) {
            realImage = new RealImage(fileName);
        }
        realImage.display();
    }
}

// 使用
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test_10mb.jpg");

        // 首次调用会加载图片
        image.display();  
        System.out.println("");

        // 第二次调用不会再加载图片,因为已经加载过了
        image.display();  
    }
}
行为型模式

行为型模式关注对象之间的通信,如何分配职责,如何在对象之间传递消息。

1. 策略模式(Strategy Pattern)

定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

使用场景

  • 多个类只有在行为上有稍许不同
  • 需要动态地选择算法时

优点

  • 算法可以自由切换
  • 避免使用多重条件判断
  • 符合开闭原则

缺点

  • 客户端必须了解所有的策略
  • 策略类数目增加会导致类膨胀

实现方式

// 策略接口
interface Strategy {
    int doOperation(int num1, int num2);
}

// 具体策略
class OperationAdd implements Strategy {
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

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

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

// 上下文
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 StrategyPatternDemo {
    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));
    }
}
2. 观察者模式(Observer Pattern)

定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

使用场景

  • 当一个对象的改变需要同时改变其他对象,且不知道具体有多少对象需要改变时
  • 对象应能够被其他对象动态添加而无需修改代码

优点

  • 支持广播通信
  • 降低了目标与观察者之间的耦合度

缺点

  • 可能导致更新频繁,影响性能
  • 可能触发级联更新

实现方式

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

// 观察者接口
interface Observer {
    void update(String message);
}

// 具体观察者
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    public void update(String message) {
        System.out.println(name + " receives message: " + message);
    }
}

// 主题接口
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers(String message);
}

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    public void registerObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver(Observer o) {
        observers.remove(o);
    }

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

    public void someBusinessLogic() {
        // 执行一些业务逻辑,然后通知观察者
        String message = "Subject has some new state.";
        this.notifyObservers(message);
    }
}

// 使用
public class ObserverPatternDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        
        Observer observer1 = new ConcreteObserver("Observer1");
        Observer observer2 = new ConcreteObserver("Observer2");
        
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        
        // 触发通知
        subject.someBusinessLogic();
        
        // 移除一个观察者
        subject.removeObserver(observer2);
        
        // 再次触发通知
        subject.someBusinessLogic();
    }
}
3. 命令模式(Command Pattern)

定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

使用场景

  • 需要将请求发送者和接收者解耦时
  • 支持撤销、重做操作的系统

优点

  • 降低系统的耦合度
  • 增加新的命令很容易,不需要修改已有代码

缺点

  • 可能导致系统中类数量增加

实现方式

// 命令接口
interface Command {
    void execute();
}

// 具体命令
class LightOnCommand implements Command {
    private Light light;

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

    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

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

    public void execute() {
        light.turnOff();
    }
}

// 接收者
class Light {
    public void turnOn() {
        System.out.println("The light is on");
    }

    public void turnOff() {
        System.out.println("The light is off");
    }
}

// 调用者
class RemoteControl {
    private Command command;

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

    public void pressButton() {
        command.execute();
    }
}

// 使用
public class CommandPatternDemo {
    public static void main(String[] args) {
        Light light = new Light();
        LightOnCommand lightOn = new LightOnCommand(light);
        LightOffCommand lightOff = new LightOffCommand(light);

        RemoteControl remote = new RemoteControl();
        
        remote.setCommand(lightOn);
        remote.pressButton();
        
        remote.setCommand(lightOff);
        remote.pressButton();
    }
}
4. 迭代器模式(Iterator Pattern)

定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的底层表示。

使用场景

  • 需要访问一个聚合对象的内容,而不暴露其内部细节时
  • 支持多种遍历方式或并行遍历时

优点

  • 它支持以不同的方式遍历一个聚合对象
  • 简化了聚合类的接口

缺点

  • 增加了类的数量

实现方式

// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 容器接口
interface Container {
    Iterator getIterator();
}

// 具体容器
class NameRepository implements Container {
    public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

    public Iterator getIterator() {
        return new NameIterator();
    }

    private class NameIterator implements Iterator {
        int index;

        public boolean hasNext() {
            return index < names.length;
        }

        public Object next() {
            if(this.hasNext()) {
                return names[index++];
            }
            return null;
        }
    }
}

// 使用
public class IteratorPatternDemo {
    public static void main(String[] args) {
        NameRepository namesRepository = new NameRepository();

        for(Iterator iter = namesRepository.getIterator(); iter.hasNext();) {
            String name = (String)iter.next();
            System.out.println("Name : " + name);
        }
    }
}
5. 状态模式(State Pattern)

定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

使用场景

  • 当一个对象的行为取决于它的状态,并且必须在运行时刻根据状态改变其行为时
  • 代码中有大量与对象状态有关的条件分支语句

优点

  • 将状态转换逻辑封装在状态类中,简化了条件复杂的代码
  • 符合开闭原则

缺点

  • 增加了系统的类数量和复杂度

实现方式

// 状态接口
interface State {
    void doAction(Context context);
}

// 具体状态
class StartState implements State {
    public void doAction(Context context) {
        System.out.println("Player is in start state");
        context.setState(this);
    }

    public String toString(){
        return "Start State";
    }
}

class StopState implements State {
    public void doAction(Context context) {
        System.out.println("Player is in stop state");
        context.setState(this);
    }

    public String toString(){
        return "Stop State";
    }
}

// 上下文
class Context {
    private State state;

    public Context() {
        state = null;
    }

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

    public State getState() {
        return state;
    }
}

// 使用
public class StatePatternDemo {
    public static void main(String[] args) {
        Context context = new Context();

        StartState startState = new StartState();
        startState.doAction(context);

        System.out.println(context.getState().toString());

        StopState stopState = new StopState();
        stopState.doAction(context);

        System.out.println(context.getState().toString());
    }
}
6. 模板方法模式(Template Method Pattern)

定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

使用场景

  • 多个子类有公共的方法,并且逻辑基本相同时
  • 重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现

优点

  • 封装不变部分,扩展可变部分
  • 提取公共代码,便于维护

缺点

  • 每一种不同的实现都需要一个子类,可能会导致类的数量增加

实现方式

// 抽象类
abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();

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

// 具体类
class Cricket extends Game {
    @Override
    void initialize() {
        System.out.println("Cricket Game Initialized! Start playing.");
    }

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

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

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

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

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

// 使用
public class TemplatePatternDemo {
    public static void main(String[] args) {
        Game game = new Cricket();
        game.play();
        System.out.println();
        game = new Football();
        game.play();
    }
}
7. 访问者模式(Visitor Pattern)

定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

使用场景

  • 一个对象结构包含许多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作
  • 需要对一个对象结构中的对象进行很多不同的且不相关的操作,而要避免让这些操作"污染"这些对象的类

优点

  • 符合单一职责原则
  • 扩展性好,增加新的操作容易

缺点

  • 增加新的元素困难
  • 破坏了封装性,因为访问者必须了解具体类的实现

实现方式

// 元素接口
interface ComputerPart {
    void accept(ComputerPartVisitor computerPartVisitor);
}

// 具体元素
class Keyboard implements ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Monitor implements ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Mouse implements ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Computer implements ComputerPart {
    ComputerPart[] parts;

    public Computer() {
        parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }

    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}

// 访问者接口
interface ComputerPartVisitor {
    void visit(Computer computer);
    void visit(Mouse mouse);
    void visit(Keyboard keyboard);
    void visit(Monitor monitor);
}

// 具体访问者
class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }

    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }

    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }

    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor.");
    }
}

// 使用
public class VisitorPatternDemo {
    public static void main(String[] args) {
        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
    }
}
结论

Java 设计模式的应用能够显著提升代码的可维护性、可扩展性和复用性。通过本文,我们详细讲解了创建型、结构型和行为型的各类设计模式,并通过具体的代码示例展示了它们的实现和应用场景。掌握这些设计模式不仅仅是对理论知识的学习,更是对编程思想和实践的提升。在实际项目中,选择合适的设计模式应结合具体的业务需求和系统架构,确保在提高代码质量和开发效率的同时,避免过度设计带来的复杂性。

你可能感兴趣的:(Java,学习,java,设计模式,单例模式)