设计模式之行为型模式

行为型模式关注流程控制。

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象无法完成的任务,涉及算法与对象间职责的分配。

  • 类行为模式:采用继承机制来在类间分派行为

  • 对象行为模式:采用组合或聚合在对象间分配行为

行为模式包括 11 种:模板方法模式、解释器模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式。仅前两种属于类行为模式。

模板方法模式

算法步骤以及步骤的执行顺序清晰,某些步骤依赖具体环境,这些步骤仅在父类声明,实现推迟到子类。

模板方法(Template Method)的角色:

  • 抽象类(Abstract Class):由一个模板方法和若干个基本方法构成。

    模板方法定义算法骨架,基本方法实现算法各个步骤,是模板方法的组成部分。基本方法又可以分为三种:抽象方法(Abstract Method) 、具体方法(Concrete Method) 、钩子方法(Hook Method) 。

  • 具体子类(Concrete Class):继承抽象类并实现抽象方法和钩子方法。

模板方法模式提高代码复用性,实现了反向控制。

适用场景:算法清晰,部分步骤易变;父类部分操作依赖于子类判断。

实现方式
// 抽象父类
public abstract class AbstractCook {
   

    /**
     * 模板方法
     * 算法步骤固定,使用final修饰,不允许改变
     */
    public final void cook() {
   
        // 1.放蔬菜
        addVegetable();
        // 2.放调料
        addDressing();
        // 3.翻炒
        stirFry();
    }

    public void addVegetable() {
   }

    // 抽象方法
    public abstract void addDressing();

    public void stirFry() {
   }
}
// 具体子类
public class TomatoCook extends AbstractCook {
   
    @Override
    public void addVegetable() {
   
        System.out.println("tomato");
    }

    @Override
    public void addDressing() {
   
        System.out.println("salt");
    }
}
// 使用者
TomatoCook ck = new TomatoCook();
ck.cook();
源码寻迹

InputStream 类的无参 read() 方法是抽象的,由子类实现,有参 read() 方法通过无参 read() 方法实现。

public abstract class InputStream{
   
    // read()推迟到子类实现
    public abstract int read();
    // 模板方法
	public int read(byte b[], int off, int len){
   
        Objects.checkFromIndexSize(off, len, b.length);
        if (len == 0) {
   
            return 0;
        }
        // this↓
        int c = read();
        if (c == -1) {
   
            return -1;
        }
        b[off] = (byte)c;
        int i = 1;
        try {
   
            for (; i < len ; i++) {
   
                // this↓
                c = read();
                if (c == -1) {
   
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
   
        }
        return i;
    }
}

策略模式

多种可相互替代的策略/算法。

策略模式(Strategy)的角色:

  • 抽象策略类(Strategy):给出所有具体策略类所需的接口。
  • 具体策略类(Concrete Strategy):实现抽象策略,提供具体的算法实现。
  • 环境类(Context):持有策略类的引用,供使用者调用。

策略模式避免使用多重条件选择语句,策略类之间可以自由切换,可结合享元模式减少策略类的创建。

适用场景:存在多个可相互独立、相互替换的算法。

实现方式
// 抽象策略
public interface Strategy {
   
    void show();
}
// 具体策略
public class SA implements Strategy {
   
    @Override
    public void show() {
   
        System.out.println("A");
    }
}
public class SB implements Strategy {
   
    @Override
    public void show() {
   
        System.out.println("B");
    }
}
// 环境
public class Context {
   

    // 持有策略类
    private Strategy strategy;

    public Context(Strategy strategy) {
   
        this.strategy = strategy;
    }

    // 调用具体策略算法
    public void show() {
   
        strategy.show();
    }

}
// 使用者
Context context = new Context(new Strategy());
context.show();
源码寻迹

Arrays 是环境类,其 sort() 方法可根据传入的策略进行排序操作。

public class Arrays {
   
	public static <T> void sort(T[] a, Comparator<? super T> c) {
   
        if (c == null) {
   
            sort(a);
        } else {
   
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }
}

命令模式

将请求封装为命令对象,发起请求方与执行请求方通过命令对象沟通。

命令模式(Command)的角色

  • 抽象命令类(Command):声明执行方法。
  • 具体命令(Concrete Command):实现命令接口,通常持有接收者,并调用接收者来完成命令。
  • 接收者(Receiver): 执行命令。
  • 请求者(Invoker):命令对象执行请求,通常持有命令对象,使用命令对象的入口。

请求者持有命令,命令持有接收者。

命令模式将调用操作的对象与实现该操作的对象解耦,可以实现宏命令,方便实现 Undo 和 Redo 操作。

适用场景:调用者和接收者解耦,不直接交互;支持命令的撤销(Undo)操作和恢复(Redo)操作。

实现方式
// 接收者
public class Chef {
   
    public void cook(String name) {
   
        System.out.println("cook " + name);
    }
}
// 抽象命令
public interface Command {
   
    void execute();
}
// 具体命令
public class OrderCommand implements Command {
   

    // 持有接收者
    private Chef chef;
    // 持有订单
    private Order order;

    public OrderCommand(Chef chef, Order order) {
   
        this.chef = chef;
        this.order = order;
    }

    @Override
    public void execute() {
   
        order.getNameList().forEach(name-> chef.cook(name));
    }

}
// 订单
public class Order {
   
    // 订单中的菜品
    private List<String> nameList;
}
// 请求者
public class Waiter {
   

    // 持有命令
    private List<Command> commandList = new ArrayList<>();

    public void addCommand(Command cmd) {
   
        commandList.add(cmd);
    }

    // 发起请求
    public void order() {
   
        commandList.forEach(Command::execute);
    }

}
// 使用者
Chef cf = new Chef();<
  • 39
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值