设计模式之行为模式

 

 

1.模板方法模式 Template Method 

   主要逻辑在父类中实现,子类只实现部分抽象方法或者钩子方法。

   钩子方法的目的是让子类能够控制模板算法中可选的部分。

   


 

 

 

 

   2.状态模式。

               context中默认有一个当前状态。

               如果有context请求都委托当前state执行,状态的切换可以再state中切换,也可以在context中切换,具体看是否需要动态切换。

               每个状态子类只需要考虑一种情况,大大提高了可维护性,每个子类状态可以包含context,从而可以控制context状态的流转。

              如果有情况新情况增加,只要添加一个state实现类即可,此处可能关联到某些状态跳转到新状态的可能性,只需要修改到需要关联的状态即可,不用修改所有的状态。如果是原来的的if else的话,可能每种情况都需要考虑了。所以此处体现了开闭原则。




 
 
 3.命令模式

   命令模式主要用于将请求者和执行者解耦。

   我觉得最经典的应用场景是线程池了,比如说我执行一个上传文件的任务, 那么我的角色就是Client, 上传文件的类UploadService就是Receiver,我生成一个UploadTask 实现runnable接口 那么UplaodTask就是具体的命令,ThreadPool是执行者就是Invoker,它只要负责执行Task的runnable方法即可。

   就拿餐厅来举个例子,如果客户Client点菜下单,这个menu就是一个commnd,这个commnd可以指定哪个厨师烧什么菜,如commnd1是厨师A烧牛排,commnd2是厨师A烧pizza和调制果汁,commnd3为厨师B烧牛排...

。客户点完菜单生成一个commnd,将commnd菜单通过setCommnd递交到服务员invoker,此时服务员invoker就具有了一个或者多个commnd。但是何时将菜单递交给厨房柜台的方法execute由服务员决定,服务员invoker可以决定有一个菜单就执行execute送菜单还是多个commnd才执行execute送菜单的服务。

   

   命令模式的使用场景

   1.队列请求,请求者将请求封装成commnd发送过来,这边开一个队列来存储源源不断的请求,再开一线程不断从队列里面拿请求。处理请求的方法很简单,不用知道具体的请求对象,和具体要做什么操作,只要执行commmnd.execute()方法即可。

   2.日志请求,请求者将操作数据库的动作封装成commnd序列化到磁盘上。如果发生宕机,则从磁盘上反序列化到Invoker,Invoker不用注重具体操作的对象和具体的动作,只要执行execute就能恢复宕机后的数据。



 

 

 

 4.迭代器模式

       迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不用暴露其内部的表示。

       Aggregate聚合接口是主体,每种集合都一个具体Aggregeta实现类,同时包含一个iterator实现类。

       使用流程从Client发起,Client先创建一个集合,通过集合可以获取Aggregate接口对象,通过Aggregate接口对象的createIterator()获取Iterator接口,通过Iterator接口来遍历对象。绕了一圈啊,但是不同的集合统一的API还是挺优美的。

 

5.策略模式

  定义了算法族,分别封装起来,让它们之间可以互相替代,此模式让算法的变化独立于使用算法的客户。

  这里讲述了部分OO原则:

      封装变化,将变化的部分抽象出来,让以后能够更灵活的修改,软件设计之初就应该开始考虑,软件设计完成之后,变化的部分相对来说会更加的明显,更需要考虑封装变化。

      多用组合,少用继承。继承的缺点即所有的子类都实现了相同的方法,冗余度会很高,继承的情况,通常只会将确定不会变化的东西封装在父类中,用于继承。

     针对接口编程,不针对实现编程。此处讲的接口不纯粹是一般意义上的接口还包含了抽象类。针对接口编程这接口定义的内容可以动态扩展,提高了代码的弹性。

 

 以下是自动发现策略、自动注册策略,使用的使用根据类型获取即可。

// 策略类接口
public interface Handler<R extends Serializable> {

    /**
     * 获得提交类型(返回值也可以使用已经存在的枚举类)
     *
     * @return 提交类型
     */
    String getSubmitType();

    /**
     * 处理表单提交请求
     *
     * @param request 请求
     * @return 响应,left 为返回给前端的提示信息,right 为业务值
     */
    CommonPairResponse<String, R> handleSubmit(Request request);
}



@Component
public class HandlerFactory implements InitializingBean, ApplicationContextAware {

    private static final Map<String, Handler<Serializable>> map = new HashMap<>(8);

    private ApplicationContext appContext;

    /**
     * 根据提交类型获取对应的处理器
     *
     * @param submitType 提交类型
     * @return 提交类型对应的处理器
     */
    public Handler<Serializable> getHandler(String submitType) {
        return map.get(submitType);
    }

    @Override
    public void afterPropertiesSet() {
        // 将 Spring 容器中所有的 Handler 注册到 map
        appContext.getBeansOfType(Handler.class)
                  .values()
                  .forEach(handler -> map.put(handler.getSubmitType(), handler));
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
        appContext = applicationContext;
    }
}

6.观察者模式

   定义了对象之间一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都能收到通知并自动更新。

   观察者模式实现了对象之间的松耦合,主题或者观察者只依赖事先定义好的接口,所以只要他们之间的接口仍然被遵守,我们就可以自由的改变他们。

    我们简单分析下类图吧,subject也称为observerable可观察对象。

    为何要添加setChanged()方法呢?这个方法主要控制变化频率吧,我们用于控制什么样的change是我们预期的change,什么样的change是可以忽略的,因为有时候可能不是希望所有的变化都通知观察者。

    为何要提供getState方法呢?因为状态分为推拉两种,如果推的话obserable不知道具体的observer需要哪些状态,所以一般只能将所有的状态推送给observer

至于拉的话我个人理解则显的更为灵活,通知观察者让他们自己去拉状态,但是这样也有个问题,观察者必须要预先知道observerable内部的状态。

    为何观察者内部需要保留observerable的引用?我认为主要涉及两点吧,第一个要拉上一个问题中的状态,第二解除观察者关系,虽然observerable中提供了方法主动权在observerable,但是observer中有了引用则更会更加灵活,observer可以方便的解除观察者关系。


 
        比如最近做了一个权限的项目,需要在货商绑定后发送通知去拉取最新的权限信息。由于货商绑定上层入口比较多,改动量比价大,而且不能保证后续功能调用绑定后同步修改,所以觉得在最底层绑定后,给上层发送通知。

方案一:generic调用上层compose服务,这果断不行啊,违反了工程实际原则了

方案二:generic发送个mq出来,上层监听。这种方案是可行的就是改起来比较麻烦。

方案三:这时候想到了观察者模式

  a )先体会了一把jdk自带的观察者模式

  b) 后续发现工程内spring 事件很好用

  c ) guava event bus

// 被观察者
@Repository
public class GenericService extends Observable {

    public void doSave() {

        // do save
        Object save = new Object();

        // begin to call jdk notify method
       notifyObservers(save);
    }
}

// 观察者
@Service
public class ComposeService implements Observer, InitializingBean {

    @Resource
    private GenericService genericService;

    @Override
    public void update(Observable o, Object arg) {
        // do something
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        genericService.addObserver(this);
    }
}


// spring 方式 注意虽然看起来是异步的,实际是同步的
// generic中使用
@Service
public class xxxServiceImpl implements xxxService {

    @Resource
    private ApplicationContext applicationContext;

    @Override
    public boolean insert(String skuId, Long auctionId) {

        // 通知上层
        notifyEvent(Lists.newArrayList(skuId));
        return (affectRow > 0);
    }

    private void notifyEvent(List<String> xxx) {
        try {
            applicationContext.publishEvent(new xxxEvent()
                .setSkuIds(skuIds));
        } catch (Exception e) {
            log.error("xxx error", e);
        }
    }
}

@Component
public class xxxEventListener {

    @EventListener
    public void onEvent(SkuAuctionBindEvent skuAuctionBindEvent) {
        // do something
    }

}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式中的行为模式共有11种,它们分别是策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式和解释器模式。这些行为模式涉及到对象之间的交互和通信,用于解决不同对象之间的行为问题。其中,策略模式用于封装一系列的算法,让算法可以动态切换;模板方法模式用于定义算法的骨架,具体的实现由子类决定;观察者模式用于定义对象之间的一对多的依赖关系,当一个对象状态发生改变时,所有依赖该对象的对象都会收到通知;迭代器模式用于遍历集合对象的元素,而不暴露集合的内部结构;任链模式用于将请求的发送者和接收者解耦,每个接收者都可以选择处理请求或者将请求传递给下一个接收者;命令模式用于将请求封装成对象,从而可以更灵活地进行参数化和传递;备忘录模式用于保存和恢复对象的状态,以便在需要时可以回滚到之前的状态;状态模式用于根据对象的内部状态改变其行为;访问者模式用于将数据结构和操作分离,从而可以在不修改数据结构的情况下定义新的操作;中介者模式用于解耦多个对象之间的交互,使得各个对象可以独立地改变其行为;解释器模式用于定义一种语言的文法,并解释语言中的表达式。这些行为模式可以在不同场景下使用,根据具体的需求选择合适的模式来解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值