JAVA 设计模式:观察者、状态、策略、模板方法、访问者

JAVA 设计模式:观察者、状态、策略、模板方法、访问者

本文将深入探讨五种常见的 Java 设计模式:观察者模式、状态模式、策略模式、模板方法模式和访问者模式,并提供丰富的实例帮助理解和应用。

1. 观察者模式 (Observer Pattern)

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

结构:

  • 主题 (Subject):被观察的对象,维护观察者列表,并提供注册、取消注册和通知观察者的方法。
  • 观察者 (Observer):依赖主题的对象,定义更新方法以响应主题状态变化。

示例:

假设我们有一个 WeatherStation 类,它负责收集天气数据并更新 Temperature 属性。我们希望多个用户 (如 Display 类) 可以实时查看温度变化。

// 主题
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 观察者
public interface Observer {
    void update(float temperature);
}

// 主题实现
public class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;

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

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

    public void notifyObservers() {
        observers.forEach(observer -> observer.update(temperature));
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
}

// 观察者实现
public class Display implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("温度更新:" + temperature + " 度");
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        Display display = new Display();
        station.registerObserver(display);
        station.setTemperature(25.5f); // 通知观察者更新
    }
}

优点:

  • 松耦合:主题和观察者之间没有直接依赖关系,降低了代码复杂度。
  • 灵活性:可根据需要添加或移除观察者,易于扩展。

应用场景:

  • 事件处理:如 GUI 事件处理、数据库监听等。
  • 通知系统:如邮件通知、短信通知等。

2. 状态模式 (State Pattern)

定义: 将一个对象的内部状态封装成不同的状态类,并允许对象根据其状态改变其行为。

结构:

  • 状态 (State):抽象状态类,定义状态的行为方法。
  • 具体状态 (ConcreteState):实现抽象状态类,定义不同状态的行为。
  • 上下文 (Context):维护当前状态,并提供切换状态的方法。

示例:

假设我们有一个 TrafficLight 类,它可以处于红灯、黄灯或绿灯三种状态。

// 状态接口
public interface State {
    void handleRequest();
}

// 具体状态
public class RedState implements State {
    @Override
    public void handleRequest() {
        System.out.println("红灯状态:停止");
    }
}

public class YellowState implements State {
    @Override
    public void handleRequest() {
        System.out.println("黄灯状态:准备");
    }
}

public class GreenState implements State {
    @Override
    public void handleRequest() {
        System.out.println("绿灯状态:通行");
    }
}

// 上下文
public class TrafficLight {
    private State state;

    public TrafficLight() {
        state = new RedState();
    }

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

    public void handleRequest() {
        state.handleRequest();
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        TrafficLight light = new TrafficLight();
        light.handleRequest(); // 输出:红灯状态:停止

        light.setState(new YellowState());
        light.handleRequest(); // 输出:黄灯状态:准备
    }
}

优点:

  • 代码可读性更高:将状态逻辑分离到不同的类中,易于理解和维护。
  • 扩展性强:可轻松添加新的状态,而不会影响其他状态逻辑。

应用场景:

  • 状态机:如游戏角色状态、流程状态等。
  • 对象生命周期管理:如用户状态管理、订单状态管理等。

3. 策略模式 (Strategy Pattern)

定义: 定义一系列算法,将每个算法封装成独立的类,并让它们可以相互替换。

结构:

  • 策略 (Strategy):抽象策略类,定义算法接口。
  • 具体策略 (ConcreteStrategy):实现抽象策略类,定义具体的算法。
  • 上下文 (Context):维护当前策略,并提供执行策略的方法。

示例:

假设我们有一个 ShoppingCart 类,它需要根据不同的折扣策略计算总价。

// 策略接口
public interface DiscountStrategy {
    double calculateDiscount(double price);
}

// 具体策略
public class NoDiscount implements DiscountStrategy {
    @Override
    public double calculateDiscount(double price) {
        return price;
    }
}

public class TenPercentDiscount implements DiscountStrategy {
    @Override
    public double calculateDiscount(double price) {
        return price * 0.9;
    }
}

// 上下文
public class ShoppingCart {
    private DiscountStrategy strategy;

    public ShoppingCart(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double getTotalPrice(double price) {
        return strategy.calculateDiscount(price);
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart(new NoDiscount());
        double total1 = cart.getTotalPrice(100); // 总价:100

        cart = new ShoppingCart(new TenPercentDiscount());
        double total2 = cart.getTotalPrice(100); // 总价:90
    }
}

优点:

  • 可扩展性:可轻松添加新的策略,而不会影响现有代码。
  • 代码可读性更高:将算法逻辑分离到不同的类中,易于理解和维护。

应用场景:

  • 算法选择:如排序算法、加密算法、压缩算法等。
  • 不同的业务规则:如不同的折扣策略、不同的配送方式等。

4. 模板方法模式 (Template Method Pattern)

定义: 定义一个算法的骨架,将一些步骤延迟到子类中实现。模板方法模式允许子类重定义算法中某些特定步骤,但不改变算法的整体结构。

结构:

  • 抽象类 (AbstractClass):定义模板方法,其中包含算法骨架,部分步骤使用抽象方法。
  • 具体子类 (ConcreteClass):实现抽象方法,完成算法的具体步骤。

示例:

假设我们有一个 Game 类,它定义了游戏的基本流程,但具体的步骤 (如游戏开始、玩家操作、游戏结束) 由子类实现。

// 抽象类
public abstract class Game {
    public void play() {
        initialize();
        start();
        while (!isOver()) {
            playTurn();
        }
        end();
    }

    protected abstract void initialize();
    protected abstract void start();
    protected abstract void playTurn();
    protected abstract boolean isOver();
    protected abstract void end();
}

// 具体子类
public class ChessGame extends Game {
    @Override
    protected void initialize() {
        System.out.println("准备棋盘...");
    }

    @Override
    protected void start() {
        System.out.println("游戏开始!");
    }

    @Override
    protected void playTurn() {
        System.out.println("玩家回合...");
    }

    @Override
    protected boolean isOver() {
        return false; // 游戏未结束
    }

    @Override
    protected void end() {
        System.out.println("游戏结束!");
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        ChessGame chess = new ChessGame();
        chess.play(); // 执行游戏流程
    }
}

优点:

  • 代码复用性高:子类可以复用模板方法中的公共代码。
  • 可扩展性强:子类可以重写抽象方法,实现不同的游戏逻辑。

应用场景:

  • 定义算法骨架,允许子类自定义部分步骤。
  • 框架设计:如数据库操作框架、网络通信框架等。

5. 访问者模式 (Visitor Pattern)

定义: 表示一个作用于某对象结构中的各元素的操作。它允许你定义新的操作,而不改变这些元素的类。

结构:

  • 访问者 (Visitor):定义访问不同元素的操作方法。
  • 具体访问者 (ConcreteVisitor):实现访问者接口,定义具体的操作。
  • 元素 (Element):接受访问者,并提供接受访问者方法。
  • 具体元素 (ConcreteElement):实现元素接口,接受访问者并执行访问者的操作。

示例:

假设我们有一个 Employee 类,它可以是 EngineerManager。我们希望根据员工类型执行不同的操作,如打印信息或计算工资。

// 访问者接口
public interface Visitor {
    void visit(Engineer engineer);
    void visit(Manager manager);
}

// 具体访问者
public class PrintVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师:" + engineer.getName());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.getName());
    }
}

public class SalaryVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师工资:" + engineer.getSalary());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理工资:" + manager.getSalary());
    }
}

// 元素接口
public interface Element {
    void accept(Visitor visitor);
}

// 具体元素
public class Engineer implements Element {
    private String name;
    private double salary;

    public Engineer(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

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

public class Manager implements Element {
    private String name;
    private double salary;

    public Manager(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

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

// 使用示例
public class Main {
    public static void main(String[] args) {
        Engineer engineer = new Engineer("张三", 10000);
        Manager manager = new Manager("李四", 20000);

        PrintVisitor printer = new PrintVisitor();
        SalaryVisitor calculator = new SalaryVisitor();

        engineer.accept(printer);
        manager.accept(printer);

        engineer.accept(calculator);
        manager.accept(calculator);
    }
}

优点:

  • 可扩展性:可轻松添加新的操作,而不会影响元素类。
  • 代码可读性更高:将操作逻辑分离到不同的访问者类中。

应用场景:

  • 处理各种操作:如打印、序列化、数据验证等。
  • 对象结构复杂:如树结构、图结构等。

总结:

这五种设计模式是 Java 开发中常用的设计模式,它们可以帮助我们编写更优雅、更易维护的代码。通过理解和应用这些模式,我们可以提高代码的复用性、可扩展性和可读性。

提示:

  • 选择合适的模式需要根据具体情况进行判断。
  • 不要为了使用模式而使用模式,应根据实际需求选择最佳方案。
  • 了解模式背后的设计思想,才能更好地应用模式。
  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯陀含

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值