设计模式理解(二)

设计模式理解(一)

十一、命令模式

命令模式是一种行为型模式,将请求以命令的形式包裹在对象里,传递给调用对象,调用对象寻找匹配的命令对象。

计算机科学领域的任何问题都可以加一个间接的中间层来解决。所以将请求者和接受者解耦就可加一层命令层。

主要角色:

抽象命令(Command):命令有通用的特性,将命令抽象成一个类,不同的命令做不同的具体实现

具体命令类(ConcreteCommand):实现抽象命令,做具体的实现。

接受者(Receiver):真正执行命令的对象。

请求者/调用者(Invoker):请求的封装发送者,它通过命令对象来执行请求,不会直接操作接收者,直接关联命令对象,间接调用到接受者的相关操作。

客户端:一般在客户端中创建调用者对象,具体的命令类去执行命令。

// 开空调
// Receiver 真正的操作对象--空调
public class AirConditionReceiver{
    public void turnOn(){
        System.out.println("开空调");
    }
    public void turnOff(){
        System.out.println("关空调");
    }
}

// Command 抽象命令类
public interface Command{
    void execute();
}

// ConcreteCommand 具体命令类--开命令、关命令
public class TurnOnCommand implements Command{
    private AirConditionerReceiver airReceiver;
    public TurnOnCommand(AirConditionerReceiver airReceiver){
        // 默认操作
        super();
        this.airReceiver = airReceiver;
    }
    
    @Override
    public void execute(){
        airReceiver.turnOn();
    }
}
public class TurnOffCommand implements Command{
    private AirConditionerReceiver airReceiver;
    public TurnOffCommand(AirConditionerReceiver airReceiver){
        // 默认操作
        super();
        this.airReceiver = airReceiver;
    }
    
    @Override
    public void execute(){
        airReceiver.turnOff();
    }
}

// Invoker 调用者/请求者(小爱):
public class Invoker{
    private Command command;
    public Invoker(Command command){
        this.command = command;
    }
    public void action(){
        System.out.print("小爱来了,很高兴为您服务==>");
        command.execute();
    }
}

// 测试代码
public static void main(String[] args){
    Command command = new TurnOnCommand(new AirConditionReceiver);
    Invoker turnOn = new Invoker(command);
    turnOn.cation(); // 小爱来了,很高兴为您服务==>开空调

    Command command = new TurnOffCommand(new AirConditionReceiver);
    Invoker turnOff = new Invoker(command);
    turnOff.cation(); // 小爱来了,很高兴为您服务==>关空调
}

注:缺点是命令过多时,类数量爆炸;优点很明显请求者与接受者解耦

拓展:

如果是多条命令,可以在内部维护一个列表(多个命令对象),添加之后依次执行。

因为执行日志的存在,需要将对象序列化保存起来(磁盘上),维护好执行的状态,在系统故障后,还能从断开的地方继续执行。

如果需要一个撤销(回滚操作),需要在抽象类中加一个undo(),此处中间过程需要维护一个状态(类似数据库的事务回滚)

十二、责任链模式

责任链是一种行为设计模式,允许将请求沿着处理链进行传递处理。责任链模式将一系列处理责任节点视为一个整体,业务请求者不用关心内部业务逻辑与流程。当一个业务需要一系列业务对象去处理时,可将这些业务对象串联作为一条业务责任链,最终实现请求者与响应者的解耦。

主要角色:

Handler:抽象的处理者,定义一个处理请求的接口。

ConcreteHandler:具体的处理者,处理自己负责的请求,可以继续访问其下一个处理者,如果可以处理当前请求则处理,否则就交予下一个处理者,形成一条链。

Request:请求。

例:组装高达,并装好放入透明盒子,最后放到展柜

// Handler 抽象处理者
public interface Handler{
    // 设置下一个处理者
    Handler setNext(Handler handler);
    // 业务处理
    void process(Request request);
}

// 抽象-模板方法,抽象子链中的共同方法
public abstract class AbstractHandler implements Handler{
    private Handler handler;
    @Override
    public void process(Request request){
        // 模板方法定义子类的处理
        if(!doprocess(request) && this.handler != null){
            handler.procee(request);
        }
    }
    
    @Override
    public Handler nextHandler(Handler handler){
        this.handler = handler;
        return hanler;
    }
    
    abstract boolean doProcess(Request request);
}

// 具体实现--拼接
public class AssemblyHandler extends AbstractHandler{
    @Override
    boolean doprocess(Request request){
        if(Objects.equals(request.getStatus(),Constants.UNASSEMBLY.getcode())){
            //业务处理,拼接模块
            assembly();
            return true;
        }
        return false;
    }
}

//  具体实现--装盒
public class BoxingHandler extends AbstractHandler{
    @Override
    boolean doprocess(Request request){
        if(Objects.equals(request.getStatus(),Constants.UNBOXING.getcode())){
            //业务处理,拼接模块
            boxing();
            return true;
        }
        return false;
    }
}

//  具体实现--放入展柜
public class ExhibitHandler extends AbstractHandler{
    @Override
    boolean doprocess(Request request){
        if(Objects.equals(request.getStatus(),Constants.UNEXHIBIT.getcode())){
            //业务处理,拼接模块
            Exhibit();
            return true;
        }
        return false;
    }
}

// 管理器
public class HandlerManage{
    public static Handler handler;
    static{
        Handler assemblyHandler = new AssemblyHandler();
        Handler boxingHandler = new BoxingHandler();
        Handler exhibitHandler = new ExhibitHandler();
        
        // 设置处理链
        assemblyHandler.nextHandler(boxingHandler);
        boxingHandler.nextHandler(exhibitHandler);
        handler = assemblyHandler;
    }
}

// 测试代码
public static void main(String[] args){
    Request request = new BlockRequest(Constants.UNEXHIBIT.getcode());
    HandlerManage.handler.process(request);
} 

小结:

1、通过将一系列的处理封装好,请求不用关心整个处理过程。

2、封装好的意味着,不易变更处理。

3、将JavaWeb的Filter的责任链思想借来用用,重点是读书人的借;维护一个集合(处理者的集合),将处理者使用自定义注解按序配置,再将设置下一个处理者的代码改为遍历集合依次处理,达到可配置的责任链条。

十三、备忘录模式

备忘录模式是一种行为型模式,目标是在不破坏封装的前提下,捕获一个对象的内部状态,在该对象之外保存这个状态,用于将对象恢复到之前保存的状态。

分为两部分理解:一是存储副本,便于后续恢复;二是要不违背封装原则的前提下进行对象的备份和恢复。

主要角色:

Originator(发起人):负责创建一个备忘录,记录当前时刻自身的内部状态,并可以使用备份恢复内部状态。

Mementor(备忘录):负责存储发起人的内部状态,通常包含一个或者多个属性,用于表示发起人的状态。

Caretaker(负责人):负责保存备忘录,但不对备忘录的内容进行操作或检查。

适用场景:

需要保存一个对象的当前状态以便后续可恢复,例如:撤销、恢复、保存游戏进度。

实现可回滚的事务操作,也很适用。

// Memento--备忘录
public Class Memento{

    private String state;
    public Memento(String state){
        this.state = state;
    }
    public String getState(){
        return this.state;
    }
    public void setState(String state){
        this.state = state;
    }
}

// Originator--发起人
public class Originator {
    // 内部状态
    private String state;
    
    public String getState(){
        return this.state;
    }
    public void setState(String state){
        this.state = state;
    }
    // 创建一个备忘录
    public Memento createMemento(){
        return new Memento(this.state);
    }
    // 从备忘录恢复
    public void restoreMemento(Memento memento){
        this.setState(memento.getState());
    }
}

// Caretaker--负责人
public class Caretaker{
    // 备忘录对象
    private Memento memento;
    public Memento getMemento(){
        return this.memento;
    }
    public void storeMemento(Memento memento){
        this.memento = memento;
    }
}

public static void main(String[] args){
    // 发起人
    Originator originator = new Originator();
    originator.setState("1");
    System.out.println(originator.getState()); // 1
    // 负责人
    Caretaker caretaker = new Caretaker();
    caretaker.storeMemento(originator.createMemento());
    origiantor.setState("2"); 
    System.out.println(originator.getState()); // 2
    // 管理发起人的备忘录
    caretaker.storeMemento(originator.createMemento());
    originator.setState("3");
    System.out.println(originator.getState()); // 3
    
    // 回滚
    originator.restoreMemento(caretaker.getMemento());
    System.out.println(originator.getState()); // 2
}

小结:

备忘录模式:防丢失、撤销操作、恢复操作。

针对大对象:不同业务场景进行不同的处理,如:只备份必要的恢复信息、结合新数据恢复、全量备份与增量备份结合、低频全量备份、高频增量备份。

十四、观察者模式

观察者模式是一种对象行为型模式,又称为发布-订阅模式、模型-视图模式,符合依赖倒置原则。

观察者模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

示例:请假批假流程,一天只需要经理签字,三天需要主管签字,五天需要总经理,7天需要hr。

// 观察者的顶层接口
public interface observerInterface<T> {
    // 注册监听者
    public void registerListener(T t);
    // 移除监听者
    public void removeListener(T t);
    // 通知监听者
    public void notifyListener(DataEvent t);
}

// Listener顶级接口,为了抽象Listener
public interface MyListener{
    void onEvent(DataEvent event);
}

// Event抽象事件接口
public abstract class DataEvent {
    private String msg;
}

// 观察者(同步)
@Component
public class LoopObserverImpl implements ObserverInterface<MyListener>{
    // 监听者的注册列表
    private List<Listener> listenerList = new ArrayList<>();
    
    @Override
    public void registerListener(Mylistener listener){
        listenerList.add(listener); 
    }

    @Override
    public void removeListener(Mylistener listener){
        listenerList.remove(listener);    
    }

    @Override
    public void notifyListener(DataEvent event){
        for(Mylistener myListener : listenerList){
            myListener.onEvent(event);   
        }
    }
}

// 请假事件--事件的实现类
public class VacationDataEvent extends DataEvent{
    private Integer days;
}

// 监听者的实现类--经理
@Component
public class ManageListener implements Mylistener{
    @Override
    public void onEvent(DataEvent dataEvent){
        if(dataEvent instanceof VacationDataEvent){
            if(dataEvent.days < 1){
                throw new IllegeException("瞎搞,扣钱");
            }if else(dataEvent.days < 3){
                System.out.println("同意");
            }else{
                System.out.println("等待主管同意");
            }
        }
    }
}

// 监听者的实现类--主管
@Component
public class SupervisorListener implements Mylistener{
    @Override
    public void onEvent(DataEvent dataEvent){
        if(dataEvent instanceof VacationDataEvent){
            if(dataEvent.days < 3){
                return;
            }if else(dataEvent.days < 5){
                System.out.println("同意");
            }else{
                System.out.println("等待总经理同意");
            }
        }
    }
}

// 监听者的实现类--总经理
@Component
public class GeneralListener implements Mylistener{
    @Override
    public void onEvent(DataEvent dataEvent){
        if(dataEvent instanceof VacationDataEvent){
            if(dataEvent.days < 5){
                return;
            }if else(dataEvent.days < 7){
                System.out.println("同意");
            }else{
                System.out.println("等待hr给离职申请书");
            }
        }
    }
}

// 测试代码
public static void main(String[] args){
    AnnotationConfigApplicatonContext context = new AnnotationConfigApplicationContext("com.example.demo.observer.design");
    //从spring容器中获取对应bean的实例
    LoopObserverImpl loopObserver = context.getBean(LoopObserverImpl.class);
    ManageListener mal = context.getBean(ManageListener.class);
    SupervisorListener sul = context.getBean(SupervisorListener.class);
    GeneralListener gel = context.getBean(GeneralListener.class);
    
    //向观察者中注册listener
    loopObserver.registerListener(mal);
    loopObserver.registerListener(sul);
    loopObserver.registerListener(gel);
    VacationDataEvent vacationDataEvent = new VacationDataEvent();
    vacationDataEvent.setMsg("请假");
    vacationDataEvent.setDays(3);
    //发布请假事件,通知监听者
    loopObserver.notifyListener(vacationDataEvent);
}

如果想改造为异步形式,可以在观察者中引入线程池与阻塞队列。

/**
 * 启动一个线程循环阻塞队列的观察者,可以实现解耦异步。
 */
@Component
public class QueueObserverImpl implements ObserverInterface<MyListener> {
    //监听者的注册列表
    private List<MyListener> listenerList = new ArrayList<>();
    //创建一个大小为10的阻塞队列
    private BlockingQueue<DataEvent> queue = new LinkedBlockingQueue<>(10);
    //创建一个线程池
    private ExecutorService executorService = new ScheduledThreadPoolExecutor(1, r -> {
        Thread t = new Thread(r);
        t.setName("com.kangarooking.observer.worker");
        t.setDaemon(false);
        return t;
    });
//    private ExecutorService executorService = Executors.newFixedThreadPool(1);

    @Override
    public void registerListener(MyListener listener) {
        listenerList.add(listener);
    }

    @Override
    public void removeListener(MyListener listener) {
        listenerList.remove(listener);
    }

    @Override
    public void notifyListener(DataEvent event) {
        System.out.println("向队列放入DataMsg:" + event.getMsg());
        queue.offer(event);
    }

    @PostConstruct
    public void initObserver() {
        System.out.println("初始化时启动一个线程");
        executorService.submit(() -> {
            while (true) {
                try {
                    System.out.println("循环从阻塞队列里面获取数据,take是阻塞队列没有数据就会阻塞住");
                    DataEvent dataMsg = queue.take();
                    System.out.println("从阻塞队列获取到数据:" + dataMsg.getMsg());
                    eventNotify(dataMsg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void eventNotify(DataEvent event) {
        System.out.println("循环所有的监听者");
        for (MyListener myListener : listenerList) {
            myListener.onEvent(event);
        }
    }
}

上述例子看起来很牵强,没错就是为了体验本设计模式故意玩的,但若是加入下一个事件(团建),阁下怎么应对呢?

// 团建事件--事件的实现类
public class ActivityDataEvent extends DataEvent{
    private String activity;
}

// Listener顶级接口,为了抽象Listener
public interface MyListener{
    void onEvent(DataEvent event);
    void onEventTwo(DataEvent event);
}

// 剩下的当然是总经理提出要团建的想法,各位兄弟接收到消息立刻反馈出各自活动名,但是由于经费不足
// 只能改为周六免费加班一天的狗血剧情啦!

十五、模板模式

模板模式是一种行为型模式,指在父类中定义处理流程的框架,将具体实现滞后到具体子类中。

主要角色:

Abstract(抽象类):声明模板方法中要用的抽象方法及定义模板方法的实现流程。

Concrete(具体实现类):实现抽象类中定义的抽象方法。

// 媳妇要喝咖啡
// 抽象类
public abstract class DrinkCoffee{
    // 选择容器(悲剧的开始)
    public abstract void chooseContainer();
    // 选择工具(入口的难题)
    public abstract void chooseTool();
    // 选择冷却时间(破冰的坚忍)
    public abstract void chooseCoolTime();
    // 有人选择喝coffee
    public void peopleDrinkCoffee(){
        this.chooseContainer();
        this.chooseTool();
        this.chooseCoolTime();
    }
} 

// 具体实现类
// 媳妇
public abstract class WifeDrinkCoffee{
    // 选择容器(悲剧的开始)
    @Override
    public void chooseContainer(){
        System.out.println("夜光杯");
    };
    // 选择工具(入口的难题)
    @Override
    public void chooseTool(){
        System.out.println("朴实无华的鎏金勺");
    };
    // 选择冷却时间(破冰的坚忍)
    @Override
    public void chooseCoolTime(){
        System.out.println("静置3秒后,让老公喝一口,静置3分钟后,老公喝一口,静置10分钟后,
        老婆喝完");
    };
} 

// 残酷例子就不举了,还是回家吧,下雨收衣服啦

过于简单、残酷,不予以总结。

未完待续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值