行为型设计模式

16
五月
2021

行为型设计模式

文章目录

  • 行为型设计模式
    • 模板模式
    • 命令模式
    • 访问者模式
    • 迭代器模式
    • 观察者模式
    • 中介者模式
    • 备忘录模式Memento
    • 解释器模式
    • 策略模式
    • 职责链模式

该文章为个人学习总结,仍有未完善地方,案例以尚硅谷为例。

模板模式

  • 定义:通过抽象类定义好的抽象行为,将公共的行为抽象出来,通过抽象来调用,让具体类去实现。
  • 思想:就是定义抽象类,将多个类的公共方法和属性进行抽象出来,是我们最常使用的模式。不过模板方法与建造者模式不同之处在于,模板模式目的在于抽象出公共的互相联系的方法调用,其中部分方法甚至需要具体子类去实现,而建造者模式则在于创建一个对象。 模板模式可以说是对继承抽象类的使用讲解了更丰富的用法。
  • 钩子方法:在抽象类中定义一个空方法,该方法由子类去决定是否重写,当重写后来改变公共方法的执行过程。
    应用场景
    Spring中的ConfigurableApplicationContext中使用了模板模式。

案例代码

public abstract class BaoZi {
    public void makeBaoZi(){
        prepare();
        makeCheek();
        wrapper();
        steam();

    }
    public void prepare(){
        System.out.println("和面团");
    }
    public void makeCheek(){
        System.out.println("做面皮");
    }
    public void wrapper(){
        if (hasStuffing()){
            System.out.println("包"+stuffing()+"包子");
        }else {
            System.out.println("做馒头");
        }
    }
    public void steam(){
        System.out.println("蒸煮中");
    }
    public abstract String stuffing();
    public  boolean hasStuffing(){
        return true;
    }

}
public class BeefBaoZi extends BaoZi {
    @Override
    public String stuffing() {
        return "牛肉";
    }
}
public class VegetableBaoZi extends BaoZi {
    @Override
    public String stuffing() {
        return "酸菜";
    }
}
public class TemplateTest {
    public static void main(String[] args) {
        VegetableBaoZi vegetableBaoZi = new VegetableBaoZi();
        vegetableBaoZi.makeBaoZi();
        BeefBaoZi beefBaoZi = new BeefBaoZi();
        beefBaoZi.makeBaoZi();
    }
}

命令模式

  • 定义:将请求者发送者和请求接收者间的耦合消除,也即将请求封装到一个对象中,接收者引用一个抽象接口来接收,实现和扩展更加灵活。涉及的对象一般为三个:请求者,请求和接收者。
  • 思想:接收者属于被动对象,应组合或聚合在请求对象中,而请求对象通过抽象接口聚合或组合在发送者中。当需要扩展时,只需实现请求的抽象类,并将接收者组合或聚合在具体请求中。这提供了统一的处理模式,对请求者来说只需传入请求体和接收者,便可通过统一的接口来调用函数。
  • 应用:当需要通过统一的接口函数来实现对不同对象的相似操作时,可令请求来实现对接收者的具体操作,而发送者只要开启操作便可。
  • 应用场景:jdbcTemplate

UML
在这里插入图片描述

代码案例

public abstract class Command {
    public abstract void execute();
    public abstract void undo();
}
public class LightOffCommand extends Command{
    private LightReceiverCommand lightReceiverCommand;

    public LightOffCommand(LightReceiverCommand lightReceiverCommand) {
        this.lightReceiverCommand = lightReceiverCommand;
    }

    @Override
        public void execute(){
            System.out.println("关灯信号");
        lightReceiverCommand.off();
    }

    @Override
    public void undo() {
        lightReceiverCommand.on();
    }

}
public class LightOnCommand extends Command{
    private LightReceiverCommand lightReceiverCommand;

    public LightOnCommand(LightReceiverCommand lightReceiverCommand) {
        this.lightReceiverCommand = lightReceiverCommand;
    }

    @Override
    public void execute(){
        System.out.println("开灯信号");
        lightReceiverCommand.on();
    }

    @Override
    public void undo() {
        lightReceiverCommand.off();
    }
}
public class LightReceiverCommand {
    public void on(){
        System.out.println("灯开了");
    }
    public void off(){
        System.out.println("灯关了");
    }
}
public class RemoteController {
    private Command[] onCommands  ;
    private Command[] offCommands ;
    private Command undoCommand;

    public RemoteController() {
        this.onCommands  =new Command[5];;
        this.offCommands  = new Command[5];
        for (int i = 0; i < 5; i++) {
            this.offCommands[i] = new NoCommand();
            this.onCommands[i] = new NoCommand();
        }
    }
    public void setCommand(int num,Command onCommand,Command offCommand){
        this.onCommands[num] = onCommand;
        this.offCommands[num] = offCommand;
    }
    public void onButtonWasPushed(int num){
        (undoCommand=this.onCommands[num]).execute();

    }
    public void offButtonWasPushed(int num){
        (undoCommand=this.offCommands[num]).execute();
    }

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

}
public class OrderTest {
    public static void main(String[] args) {
        LightReceiverCommand light = new LightReceiverCommand();
        LightOnCommand onCommand = new LightOnCommand(light);
        LightOffCommand offCommand = new LightOffCommand(light);
        RemoteController controller = new RemoteController();
        controller.setCommand(0,onCommand,offCommand);
        controller.onButtonWasPushed(0);
        controller.undo();
    }
}

访问者模式

  • 定义:在被访问的类里面添加一个接待访问者的接口,访问者进入后便通过被访问的类来做出相应的功能。
  • 双分派:将具体状态作为参数传入对象,为一次分派,在将该对象作为参数传入给具体状态,为第二次分派。双分派能达到解耦的效果,可对两者进行同时初始化操作。
  • 注意:这种模式适合根据被访问的对象不同,而改变访问者执行形式的情况,但由于在抽象层使用了双分派,所以抽象层的耦合性增加,改变时需要对两个抽象层都进行修改。

代码

public interface  Person {
     default  void getAction(Action action){
        action.getResult(this);
    }
}
public class Man implements Person {
    /**
     * 双分派
     * @param action
     */
    @Override
    public void getAction(Action action) {
        action.getResult(this);
    }
}
public class Woman implements Person {
    @Override
    public void getAction(Action action) {
        action.getResult(this);
    }
}

public abstract class Action {
    public abstract void getResult(Man man);
    public abstract void getResult(Woman woman);
    public abstract void getResult(Person person);
}
public class Success extends Action {
    @Override
    public void getResult(Man man) {

        System.out.println("男嘉宾觉得ok");
    }

    @Override
    public void getResult(Woman woman) {
        System.out.println("女嘉宾觉得ok");

    }

    @Override
    public void getResult(Person person) {

        System.out.println("其它人觉得ok");
    }
}

public class Fail extends Action
{
    @Override
    public void getResult(Man man) {
        System.out.println("男嘉宾觉得不行");
    }

    @Override
    public void getResult(Woman woman) {
        System.out.println("女嘉宾觉得不行");

    }

    @Override
    public void getResult(Person person) {

    }
}
public class Client {
    public static void main(String[] args) {
        Person man = new Man();
        Person woman = new Woman();
        Action success = new Success();
        man.getAction(success);
        woman.getAction(success);
        Girl girl = new Girl();
        girl.getAction(success);
        Action fail = new Fail();
        man.getAction(fail);

    }
}

迭代器模式

  • 定义:提供统一的接口来提供对不同的集合进行统一的遍历,不暴露内部数据结构。
  • 思想:需要两个接口Iterable和Iterator。前者表示其实现类的元素数据结构已经有相应的Iterator迭代器,可获取元素的迭代器,后者则根据Iterable实现类元素的数据结构,进行具体的迭代遍历实现。
  • 目的单一职责原则,迭代器很好的将管理对象的功能和迭代遍历的功能分开,这样两个功能间的耦合性降低。
  • 应用场景:在最常见的集合类Collection下的实现类都具有迭代器。而且每个迭代器都在实现类内部。
  • 思考:迭代器
    类图
    在这里插入图片描述
    每个Iterable的实现类都会有对应的Iterator具体的迭代器,这里迭代器也可以组合在其内部。
    案例代码
public class Department {
    private String name;
    private String desc;

    public Department(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class ComputerCollegeIterator implements Iterator {
    private Department[] departments;
    private int position = 0;
    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        return !(position>=departments.length||departments[position]==null);
    }

    @Override
    public Object next() {
        return departments[position++];
    }

    @Override
    public void remove() {

    }
}
public class InfoCollegeIterator implements Iterator {
   private List<Department> departments;
   private int index = -1;

    public InfoCollegeIterator(List<Department> departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        if (index>=departments.size()-1){ return false; }
        else{
            index++;
            return true;
        }
    }

    @Override
    public Object next() {
        return departments.get(index);
    }

    @Override
    public void remove() {

    }

}
public class InfoCollege implements College {
   private List<Department> departments;

    public InfoCollege() {
        this.departments = new ArrayList<>();
        addDepartment("信息专业","信息安全专业");
        addDepartment("网络专业","网络安全专业");
        addDepartment("服务器专业","服务器安全专业");

    }

    @Override
    public String getName() {
        return "信息工程学院";
    }

    @Override
    public void addDepartment(String name, String desc) {
        departments.add(new Department(name,desc));
    }

    @Override
    public Iterator getIterator() {
        return new InfoCollegeIterator(departments);
    }
}
public class ComputerCollege implements  College{
    private Department[] departments;
    private int numOfDepartment = 0;

    public ComputerCollege() {
        this.departments = new Department[3];
        addDepartment("java","计算机程序语言");
        addDepartment("PHP","PHP专业");
        addDepartment("大数据","大数据专业");
    }

    @Override
    public String getName() {
        return "计算机学院";
    }

    @Override
    public void addDepartment(String name,String desc) {
        Department department = new Department(name,desc);
        departments[numOfDepartment++] = department;
    }

    @Override
    public Iterator getIterator() {
        return new ComputerCollegeIterator(departments);
    }
}
public interface College {
    public String getName();
    public void addDepartment(String name,String desc);
    public Iterator getIterator();
}
public class PrintOutPut {
    private List<College> colleges;

    public PrintOutPut(List<College> colleges) {
        this.colleges = colleges;
    }

    public void printAll(){
        Iterator<College> iterator = colleges.iterator();
        while (iterator.hasNext()){
            College college = iterator.next();
            System.out.println("========="+college.getName()+"========");
            printDepartment(college.getIterator());
        }
    }
    public void printDepartment(Iterator iterator){
        while (iterator.hasNext()){
            Department department = (Department) iterator.next();
            System.out.println(department.getName() + department.getDesc());
        }
    }
}
public class IteratorTest {
    public static void main(String[] args) {
        Set set = new HashSet();
        Iterator iterator = set.iterator();
        ArrayList<College> colleges = new ArrayList<>();
        colleges.add(new ComputerCollege());
        colleges.add(new InfoCollege());
        PrintOutPut printOutPut = new PrintOutPut(colleges);
        printOutPut.printAll();
    }
}

观察者模式

  • 定义:对象间多对一依赖的一种处理方案,当一的一端发生改变时,自动维护更新多的一端的状态。
  • 思想:在被观察者内部维护一个观察者链表,当被观察者数据发送改变时,遍历通知观察者传递改变后的参数。
  • 不足:当改变的状态较多时,显得复杂,可理解性差。可以将数据封装为对象或抽象类。

此外,在观察者模式的基础上演变出监听者模式。
类图
在这里插入图片描述

代码

public interface IObservable {
    //    添加观察者
    void addObserve(IObserve observable);
    //    删除观察者
    void removeObserve(IObserve observable);
    //    向观察者发送信息
    void notifyObservers(String message);
}

public interface IObserve {
    //    观察者处理被观察者发送过来额信息
    void handleNotify(String message);
}
public class FistObserve implements IObserve {
    @Override
    public void handleNotify(String message) {
        System.out.println("1号接受的消息" + message);
    }
}
public class SecondObserve implements IObserve {
    @Override
    public void handleNotify(String message) {
        System.out.println("2号接受的消息"+message);
    }
}
public class Test {
    public static void main(String[] args) {
        //创建多个观察者
        IObserve iObserve1 = new FistObserve();
        IObserve iObserve2 = new SecondObserve();
        //创建被观察者
        Some some =new Some();
        //被观察者添加观察者
        some.addObserve(iObserve1);
        some.addObserve(iObserve2);
        //被观察者向观察者发送信息
        some.notifyObservers("GOGOGOGOGOGO");
        //删除观察者后
        some.removeObserve(iObserve1);
        some.notifyObservers("GO ");
        Observable observable;

    }
}

监听者模式
监听器设计模式是观察者设计模式的一种实现。他与观察者设计模式不同点有

  • 1.一个被观察者只能有一个观察者对象,而不是多个

  • 2.被监听者(事件源)的状态改变,被定义为一个对象,称为事件,而不是字符串

  • 3.监听器(监听者)负责监听发生在事件源上的事件.

  • 事件源(被监听对象,产生事件的对象):提供订阅与取消监听者的方法,并负责维护监听者列表,发送事件给监听者

  • 事件处理器
    监听器的成员方法,当时事件发生后会触发对应的处理器(成员方法)。

一般情况下,监听器对象被事件触发后,都是需要从事件中获取到事件源对象,然后再从事件源中获取一些数据。也就是说,在事件对象中一般需要提供获取事件源对象的方法,当然,除了获取事件源方法外,根据业务需求,事件对象一般还需要提供一些其他的数据,以便让监听器获取。

监听器在进行工作时,可以分为以下步骤

1.将监听器绑定到事件源(注册监听器)
2.事件发生后触发监听器的成员方法,即事件处理器,传递事件对象
3.事件处理器通过事件对象获得事件源,并对事件源进行处理。

在监听器模式下,监听器负责对产生的事件对象给予的信息作出相应的处理;事件对象是根据事件源情况而生成的,

并给自己定义出某一确定的事件类型供监听器获取后进行抉择;事件源则通过注册监听器,并将生产出的事件触发监听器。

监听器模式相较于观察者模式,多了一个中间的事件对象,且由该对象触发监听器而不是一个基本参数。

也就是说,事件对象可以封装更加丰富的需要供处理的数据给监听器。

类图
在这里插入图片描述
代码案例
事件类,当传递一个事件时,顺便把产生该事件的事件源携带过去。

//通常对于事件对象,我们一般需要从事件对象中获取到事件源对象
public interface ICurdEvent{
    //声明事件类型
    String Create_EVENT = "create event";
    String Update_EVENT = "update event";
    String Retrieve_EVENT = "retrieve event";
    String Delete_EVENT = "delete event";

    //获取事件源对象
    IListenerable getEventSource();
    //获取事件类型
    String getEventType();

}

监听者,类似于观察者

public interface IListener {
    void handle(ICurdEvent event);
}

被监听者,里面注册监听者,并提供触发器,当调用触发器的方法时,会产生相应的带有不同标志的

public interface IListenerable {
    //为事件源注册监听器
    void setListener(IListener listener);
    //触发监听器
    void triggerListener(ICurdEvent event);
}

事件类,通过被监听者触发了什么条件,传入对应的触发标志构造对应的事件对象,本身与监听者共同规定了约束。

//事件对象。事件对象保存了一些需要的数据之外,还带有事件源信息eventSource
public class CurdEvent implements ICurdEvent {
    private IListenerable eventSource;  //事件源
    private String methodname;          //事件源所执行的方法名称
    public CurdEvent(IListenerable eventSource,String methodname){
        this.eventSource = eventSource;
        this.methodname = methodname;
    }
    @Override
    public IListenerable getEventSource() {
        return eventSource;
    }
    //根据事件源所执行的不同的方法返回不同的事件类型
    @Override
    public String getEventType() {
        String eventType = null;
        if (methodname.startsWith("save")){
            eventType = Create_EVENT;
        }else if (methodname.startsWith("remove")){
            eventType = Delete_EVENT;
        }else if (methodname.startsWith("modify")){//修改
            eventType = Update_EVENT;
        }else if (methodname.startsWith("find")){
            eventType = Retrieve_EVENT;
        }else {
            eventType = "have not this event type";
        }
        return eventType;
    }
}

测试

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

        //定义监听器
        IListener listener = new Listener();
        //定义事件源
        Some some = new Some();
        //事件源注册监听器
        some.setListener(listener);
        some.saveStudent();
        some.removeStudent();
    }
}

中介者模式

  • 定义:用一个中介对象封装对象之间的交互。中介者使服务的对象之间不需要互相显示的调用。将调用封装到中介者中,从而降低子系统耦合性。
  • 思想:让中介者通过数据结构保存所有参与的对象的引用信息,并将对象间的交互行为在中介者内部定义,而对象则保有中介者引用。当触发时,通过参数和自身信息,让中介者找到指定方法,然后调用关系函数进行处理。

UML类图
在这里插入图片描述

备忘录模式Memento

定义:在不破化封装性的前提下,捕获该对象的状态,并在外部保存,之后用于恢复到原先的状态。
思想:用一个对象memento来保存另一个对象的状态。当要恢复时,传入memento并获取里面保存的状态。

注意:频繁的备忘容易消耗太多资源。
适用:存档,回退,事务回滚等。

代码

public class CareTaker {
    private List<Memento> mementos = new ArrayList<>();
    public void add(Memento memento){
        mementos.add(memento);
    }

    public Memento getMemento(int index){
        return mementos.get(index);
    }
}
public class Memento {
    private String state;

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

    public String getState() {
        return state;
    }
}

public class Originator {
    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    public Memento saveMemento(){
        return new Memento(this.state);
    }

    public void getFromMemento(Memento memento){
        state = memento.getState();
    }
}
public class Test {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("攻击力:100");
        System.out.println(originator.getState());
        CareTaker careTaker = new CareTaker();
        careTaker.add(originator.saveMemento());
        originator.setState("攻击力:999");
        System.out.println(originator.getState());
        originator.getFromMemento(careTaker.getMemento(0));
        System.out.println("恢复到"+originator.getState());
    }
}

解释器模式

定义:给定一个语言或表达式,定义它的文法的一种表示,并定义一个解释器来解释该语言。

代码

public abstract class Expression {
    public abstract int interpreter(HashMap<String,Integer> var);
}
public class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var)-super.right.interpreter(var);
    }
}
public  abstract  class SymbolExpression extends Expression {
    protected Expression left;
    protected Expression right;

    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
}

策略模式

定义:将超类中可能因子类的不同情况发生变化的部分封装成接口,将算法的实现从行为分离出来。

场景:在子类多层继承并重写父类方法时,会使得子类都需要重写父类的方法,使得父类失去了其存在价值,所以需要将父类可能需要重写的方法封装成一个接口聚合在父类中,由子类去具体决定行为,未提供具体的行为的子类仍可使用父类的方法。将变化从稳定中抽离出来,可以让变化部分彼此隔离,即便是多层继承,也互不影响。

JDK使用场景
Comparator接口是一个行为的策略接口。
类图
在这里插入图片描述
代码


public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;

    public  void fly(){
        if (flyBehavior!=null){
            flyBehavior.fly();
        }else {
            System.out.println("会飞翔");
        }

    }

    public void swimming(){
        System.out.println("会游泳");
    }

    public void quack(){
        if (quackBehavior!=null){
            quackBehavior.quack();
        }else {
            System.out.println("会嘎嘎叫");
        }
    }
}
public interface FlyBehavior {
   void fly();
}
public class NoFlyBehavior implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("不会飞");
    }
}
public interface QuackBehavior {
    void quack();
}
public class NoQuackBehavior implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("无法叫");
    }
}

public class ToyDuck extends Duck {
    public ToyDuck(){
        flyBehavior = new NoFlyBehavior();
        quackBehavior = new NoQuackBehavior();
    }
}
public class WildDuck extends Duck {
}

public class Test {
    public static void main(String[] args) {
        WildDuck wildDuck = new WildDuck();
        wildDuck.fly();
        wildDuck.quack();
        wildDuck.swimming();
        ToyDuck toyDuck = new ToyDuck();
        toyDuck.quack();
        toyDuck.swimming();
        toyDuck.fly();
    }
}

职责链模式

定义:将请求和处理逻辑分离,实现解耦,提高系统的灵活性。
缺点:当处理链增长时会导致性能降低,可以在Handler中设置最大节点数,判断是否超过最大数,超过则限制放入。
应用场景:多级请求,多层的判断或多级处理。

类图
在这里插入图片描述
代码

public abstract class Approver {
    Approver approver;
    String name;

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

    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    public abstract void processRequest(PurchaseRequest purchaseRequest);
}
public class CollegeApprover extends Approver {
    public CollegeApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice()>=5000&&purchaseRequest.getPrice()<10000){
            System.out.println("被"+name+"处理了");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }
}
public class DepartmentApprover extends Approver {
    public DepartmentApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice()<5000){
            System.out.println("被"+name+"处理");
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}

public class PurchaseRequest {
    private int type;
    private float price = 0.0f;
    private int id = 0;

    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }

    public int getType() {
        return type;
    }

    public float getPrice() {
        return price;
    }
}
public class SchoolApprover extends Approver {
    public SchoolApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice()>=15000){
            System.out.println("被"+name+"处理了");
        }else {
            System.out.println("无法处理");
        }
    }
}

public class ViceSchoolApprover extends Approver {
    public ViceSchoolApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice()>=10000&&purchaseRequest.getPrice()<15000){

            System.out.println("被"+name+"处理");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        PurchaseRequest purchaseRequest = new PurchaseRequest(1,8000,1);
        SchoolApprover schoolApprover = new SchoolApprover("校长");
        ViceSchoolApprover viceSchoolApprover = new ViceSchoolApprover("副校长");
        viceSchoolApprover.setApprover(schoolApprover);
        CollegeApprover collegeApprover = new CollegeApprover("院长");
        collegeApprover.setApprover(viceSchoolApprover);
        DepartmentApprover departmentApprover = new DepartmentApprover("系主任");
        departmentApprover.setApprover(collegeApprover);
        departmentApprover.processRequest(purchaseRequest);
    }
}
TAG

网友评论

共有访客发表了评论
请登录后再发布评论,和谐社会,请文明发言,谢谢合作! 立即登录 注册会员