Java设计模式【下】:行为型模式详解

🌈 开篇:设计模式就像乐高说明书
想象你要组装乐高城堡,行为型模式就是教你如何让各个积木块(对象)默契配合的说明书!

行为型模式
主要用于描述对象之间的通信和协作方式,包括算法、责任链、状态等方面。这些模式可以帮助我们更好地组织和管理代码,提高代码的可维护性和可扩展性。

1. 命令模式 Command Pattern:万能遥控器的秘密

命令模式将一个请求封装为一个对象,从而可以用不同的请求对客户端进行参数化。它适用于请求排队、日志记录以及支持撤销操作等场景。

使用场景

  • 解耦请求的发送者和接收者。
  • 支持命令的撤销(undo)操作。
  • 记录请求的历史记录。
  • 将简单操作组合成复杂操作。

代码实现
🎮 假设有一个电视机,它具有开机、关机和切换频道等操作
定义命令接口和具体命令类

public interface Command {
    void execute();
}

public class TvOnCommand implements Command {
    private TV tv;
    
    public TvOnCommand(TV tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.on();
    }
}

public class TvOffCommand implements Command {
    private TV tv;
    
    public TvOffCommand(TV tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.off();
    }
}

public class TvChangeChannelCommand implements Command {
    private TV tv;
    private int channel;
    
    public TvChangeChannelCommand(TV tv, int channel) {
        this.tv = tv;
        this.channel = channel;
    }
    
    public void execute() {
        tv.changeChannel(channel);
    }
}

定义接收者类

public class TV {
    public void on() {
        System.out.println("TV is on");
    }
    
    public void off() {
        System.out.println("TV is off");
    }
    
    public void changeChannel(int channel) {
        System.out.println("TV channel is changed to " + channel);
    }
}

定义调用者类

public class RemoteController {
    private Command onCommand;
    private Command offCommand;
    private Command changeChannelCommand;
    
    public RemoteController(Command onCommand, Command offCommand, Command changeChannelCommand) {
        this.onCommand = onCommand;
        this.offCommand = offCommand;
        this.changeChannelCommand = changeChannelCommand;
    }
    
    public void turnOn() {
        onCommand.execute();
    }
    
    public void turnOff() {
        offCommand.execute();
    }
    
    public void changeChannel() {
        changeChannelCommand.execute();
    }
}

使用命令模式

TV tv = new TV();
Command onCommand = new TvOnCommand(tv);
Command offCommand = new TvOffCommand(tv);
Command changeChannelCommand = new TvChangeChannelCommand(tv, 2);

RemoteController remoteController = new RemoteController(onCommand, offCommand, changeChannelCommand);
remoteController.turnOn(); // 输出 "TV is on"
remoteController.turnOff(); // 输出 "TV is off"
Command changeChannelCommand2 = new TvChangeChannelCommand(tv, 5);
RemoteController remoteController2 = new RemoteController(onCommand, offCommand, changeChannelCommand2);
remoteController2.changeChannel(); // 输出 "TV channel is changed to 5"

上述代码中,RemoteController 充当了调用者角色,TvOnCommand、TvOffCommand 和 TvChangeChannelCommand 充当了具体命令角色,而 TV 充当了接收者角色。
当 RemoteController 调用某个命令的 execute() 方法时,具体命令将通过接收者TV来执行相应的操作。通过这种方式,调用者和接收者之间的耦合得以解除。

使用小结

  • 可以使用命令模式来实现撤销和恢复操作。例如,在编辑器中,可以使用命令模式来实现对文本的撤销和恢复操作。
  • 可以使用命令模式来实现日志记录。例如,在Web应用中,可以将每个请求封装成一个命令对象,并将命令对象记录到日志文件中。
  • 可以使用命令模式来实现消息队列。例如,在JMS(Java消息服务)中,可以将每个消息封装成一个命令对象,并将命令对象加入到消息队列中。

2. 责任链模式:快递层层转包记

责任链模式通过将请求的处理对象串成一条链,使请求能够沿着这条链传递,直到有一个对象处理它。这种方式解耦了请求的发送者和接收者。
🔗 快递小哥的日常:
你的包裹从分拣中心→省站→市站→快递员,每个环节只处理自己能派送的范围,这就是责任链!

代码实现

// 处理者接口:快递节点
interface DeliveryHandler {
    void handle(Package pkg);
}

// 具体处理者:市级站点
class CityStation implements DeliveryHandler {
    private DeliveryHandler next;
    public void handle(Package pkg) {
        if (pkg.getCity().equals("北京")) {
            System.out.println("北京站派送中...");
        } else {
            next.handle(pkg); // 转给下一站
        }
    }
}

模式亮点:
🔗 动态增减处理节点
🔗 发送者无需知道最终处理者

3. 观察者模式 Observer Pattern:微信订阅号通知

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

应用场景
1.事件处理机制:Java中的Swing GUI框架就是基于观察者模式实现的,当用户与组件交互时,组件会向注册的监听器发送事件通知,以触发相应的事件处理方法。
2.日志记录:Java中的日志系统也是基于观察者模式实现的,当日志发生变化时,它会通知所有注册的观察者,例如文件输出流、控制台输出流等,从而实现日志的输出和记录。
3.用户界面设计:在Java中,用户界面设计中的许多元素都可以使用观察者模式实现,例如菜单项、按钮、文本框等,当用户与这些元素交互时,它们会向注册的监听器发送事件通知,以触发相应的事件处理方法。
4.多线程编程:在Java中,观察者模式还可以用于多线程编程中,当一个线程发生了某些变化时,它可以向其他线程发送通知,以实现线程间的协作和同步。

👀代码实现:你关注的博主发文→所有粉丝收到推送。观察者模式就是订阅-通知机制!

// 主题(博主)
class WechatOfficial {
    private List<Follower> followers = new ArrayList<>();
    
    public void postArticle(String title) {
        System.out.println("发布新文章:" + title);
        notifyFollowers(title);
    }
    
    private void notifyFollowers(String title) {
        for (Follower f : followers) {
            f.update(title);
        }
    }
}

// 观察者(粉丝)
class Follower {
    public void update(String msg) {
        System.out.println("收到通知:" + msg);
    }
}

4.状态模式 State Pattern:订单的不同状态

状态模式允许一个对象在其内部状态发生改变时改变其行为。通过将状态封装为对象,使得对象的行为依赖于状态,而不是对象本身。

使用场景

  • 对象的行为依赖于状态,并且状态可能在运行时发生改变时。
  • 代码中包含大量与状态相关的条件语句时。

🎮代码实现
订单对象,订单状态包括 “新建”、“处理中” 和 “完成” 三种状态,订单状态会随着订单处理的不同而改变。
首先,我们需要定义订单状态的接口:

public interface OrderState {
    void processOrder(Order order);
}

然后,我们定义订单状态的具体实现类,分别对应三种不同的状态

public class NewOrder implements OrderState {
    public void processOrder(Order order) {
        // 处理新建状态下的订单
        System.out.println("Processing new order.");
        order.setState(new ProcessingOrder());
    }
}

public class ProcessingOrder implements OrderState {
    public void processOrder(Order order) {
        // 处理处理中状态下的订单
        System.out.println("Processing order in progress.");
        order.setState(new CompletedOrder());
    }
}

public class CompletedOrder implements OrderState {
    public void processOrder(Order order) {
        // 处理完成状态下的订单
        System.out.println("Processing completed order.");
    }
}

最后,我们定义订单对象,并在订单对象中实现状态的切换:

public class Order {
    private OrderState state;

    public Order() {
        state = new NewOrder();
    }

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

    public void processOrder() {
        state.processOrder(this);
    }
}

使用上面定义的订单对象和订单状态对象来处理订单了:

Order order = new Order();
order.processOrder();    // Output: Processing new order.
order.processOrder();    // Output: Processing order in progress.
order.processOrder();    // Output: Processing completed order.

优势总结
🔄 状态切换不影响外部调用
🚫 避免大量if-else判断

5. 策略模式 Strategy Pattern:营销方式任你选

策略模式定义了一系列算法,将每个算法封装起来,使它们可以互换,客户端不需要关心算法的实现。

使用场景

  • 对象具有多种行为或算法时。
  • 需要减少大量的 if/else 语句时。

代码实现
假设有一个电商网站,它需要根据不同的促销策略来计算订单的价格。促销策略包括打折、满减、直降等等。
首先,我们定义一个促销策略接口,其中包含一个计算订单价格的方法

public interface PromotionStrategy {
    double calculatePrice(double price);
}

然后,我们实现具体的促销策略,例如打折、满减和直降策略:

public class DiscountPromotionStrategy implements PromotionStrategy {
    private double discount;

    public DiscountPromotionStrategy(double discount) {
        this.discount = discount;
    }

    public double calculatePrice(double price) {
        return price * (1 - discount);
    }
}

public class FullReductionPromotionStrategy implements PromotionStrategy {
    private double threshold;
    private double reduction;

    public FullReductionPromotionStrategy(double threshold, double reduction) {
        this.threshold = threshold;
        this.reduction = reduction;
    }

    public double calculatePrice(double price) {
        return price >= threshold ? price - reduction : price;
    }
}

public class DirectReductionPromotionStrategy implements PromotionStrategy {
    private double reduction;

    public DirectReductionPromotionStrategy(double reduction) {
        this.reduction = reduction;
    }

    public double calculatePrice(double price) {
        return price - reduction;
    }
}

最后,我们定义一个订单类,其中包含一个 PromotionStrategy 对象和一个 calculatePrice 方法:

public class Order {
    private double price;
    private PromotionStrategy promotionStrategy;

    public Order(double price, PromotionStrategy promotionStrategy) {
        this.price = price;
        this.promotionStrategy = promotionStrategy;
    }

    public double calculatePrice() {
        return promotionStrategy.calculatePrice(price);
    }
}

创建一个订单,并指定不同的促销策略来计算订单价格:

Order order = new Order(100, new DiscountPromotionStrategy(0.1));
double price = order.calculatePrice(); // 90

order = new Order(200, new FullReductionPromotionStrategy(150, 50));
price = order.calculatePrice(); // 150

order = new Order(300, new DirectReductionPromotionStrategy(50));
price = order.calculatePrice(); // 250

使用小结
策略模式是 Java 中经常使用的一种设计模式,它可以在很多场景中使用,比如:
1.可以使用策略模式定义多种日志记录方式(例如控制台输出、文件输出、网络传输等)并动态选择使用哪种方式进行日志记录。
2.可以使用策略模式定义多种支付方式(例如微信支付、支付宝支付、银行卡支付等)并让用户动态选择使用哪种支付方式进行支付。
3.可以使用策略模式定义多种加密算法(例如对称加密、非对称加密、哈希算法等)并让用户动态选择使用哪种加密算法进行数据加密。
通过使用策略模式,我们可以更灵活地实现不同的功能需求,并让用户根据实际情况选择最合适的策略进行操作

6. 模板方法模式 Template Method Pattern:奶茶店标准化配方

模板方法模式定义了算法的骨架,将某些步骤延迟到子类中。子类可以在不改变算法结构的情况下重新定义某些步骤。

使用场景:

  • 功能部分实现确定,另一部分不确定时使用。(可以把不确定的部分暴露出去,让子类去实现。
    换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子,比如常见的有:

  • 数据库访问的封装
  • Junit 单元测试
  • JavaWeb 的 Servlet 中关于 doGet/doPost 方法调用
  • Hibernate 中模板程序
  • Spring 中 JDBCTemlate、HibernateTemplate 等

📝 代码示例:
网红奶茶制作流程
煮茶→加料→封口→贴标签,固定流程中允许自定义加料!

// 抽象模板
abstract class MilkTeaTemplate {
    // 模板方法(final防止篡改)
    public final void makeTea() {
        brewTea();
        addTopping();
        seal();
        System.out.println("✅ 制作完成!");
    }
    
    // 抽象方法:加料由子类实现
    protected abstract void addTopping();
    
    // 通用步骤
    private void brewTea() { 
        System.out.println("🫖 煮茶中..."); 
    }
    
    private void seal() { 
        System.out.println("📦 封口处理"); 
    }
}

// 具体实现:珍珠奶茶
class BubbleTea extends MilkTeaTemplate {
    protected void addTopping() {
        System.out.println("➕ 加珍珠");
    }
}

注意:模板方法通常被申明为final,以防止子类对其进行重写。

以下模式不太常用

过滤器设计模式

允许在不改变原始对象的情况下,动态地添加或删除对象的行为。

解释器模式

给定一个语言,定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子,

迭代器模式

提供一种方法顺序访问一个聚合对象中各个元素,而不需要暴露该对象的内部表示。

中介者模式

用一个中介对象封装一系列的对象交互,使得这些对象不需要显示地相互引用,从而降低耦合度

备忘录模式

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

实际案例-组合使用

在实际开发中,我们很少只使用单一的设计模式来解决问题,而是将多种设计模式混合使用,以达到更好的效果。

工厂模式 + 单例模式

使用工厂模式来创建对象,通过单例模式来保证该工厂只有一个实例,从而减少创建对象时的开销。
首先,创建一个工厂类,该类使用单例模式来保证只有一个实例,该实例负责创建对象。然后,根据需要创建多个工厂方法,每个方法用于创建不同的对象。

public class SingletonFactory {
    private static volatile SingletonFactory instance;

    private SingletonFactory() {
        // 私有构造方法
    }

    public static SingletonFactory getInstance() {
        if (instance == null) {
            synchronized (SingletonFactory.class) {
                if (instance == null) {
                    instance = new SingletonFactory();
                }
            }
        }
        return instance;
    }

    public Object createObject(String type) {
        if ("type1".equals(type)) {
            return new Type1();
        } else if ("type2".equals(type)) {
            return new Type2();
        } else {
            throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }
}

public class Type1 {
    // 类型1实现逻辑
}

public class Type2 {
    // 类型2实现逻辑
}

SingletonFactory 类使用双重检查锁定实现了单例模式,同时提供了一个 createObject() 方法,该方法根据输入的参数来创建不同的对象。Type1 和 Type2 类分别代表了不同类型的对象,它们包含了各自的实现逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值