设计模式精炼(五): 行为型01

举报
且听风吟 发表于 2019/10/28 20:15:06 2019/10/28
【摘要】 本文将介绍设计模型之行为型01。

迭代模式(Cursor)

可以顺序地访问一个聚集中的元素而不暴露聚集的内部表象(internal representation)。
|- Java中的集合框架很多都使用的迭代模式的聚集,如Vector、ArrayList、HashSet、HashMap、Hashtable等。
例:

image.png

/**

  • 具体聚集角色类:

  • 实现了抽象聚集角色类所要求的接口,也就是createIterator()方法。此外,还有方法getElement()向外界提供聚集元素,而方法size()向外界提供聚集的大小等。
    */

image.png

/**

  •  抽象迭代子角色类
    */

image.png

/**

  • 具体迭代子角色
    */

image.png

//客户端

image.png

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

/**

  • 抽象主题角色类:把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。

  • 抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
    */

image.png

/**

  • 具体角色类:将有关状态存入具体观察者对象;

  • 在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
    */

image.png

/**

  • 抽象观察者角色类:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
    */

image.png

/**

  • 具体观察者角色类:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态协调。

  • 如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。
    */

image.png

//客户端

image.png

运行结果如下:
Attached an observer
主题状态为:new state
状态为:new state

策略模式

针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
|- 对算法的包装。
|- 简而言之:准备一组算法,并将每一个算法封装起来,使得它们可以互换。
(思路模板):

image.png

(具体事例:图书打折问题,初级会员没有折扣,中级会员9折,高级会员8折):

image.png

运行结果如下:
高级会员8折
图书最终价格为:240.0

模板方法模式

准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。
|- 不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
|- 模板方法在Servlet中的应用:使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。
|- ttpService类提供了一个service()方法,
|- 这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。
|- 这些do方法需要由HttpServlet的具体子类提供。
因此这是典型的模板方法模式。

|- 关键:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑。
例:

public abstract class AbstractTemplate {
    /**
     * 模板方法
     */

    public void templateMethod(){
        abstractMethod();
        hookMethod();
        concreteMethod();
    }
    //基本方法(由子类实现)
    protected abstract void abstractMethod();
    //基本方法(空方法)
    protected void hookMethod(){}
    //基本方法(已经实现)
    protected final void concreteMethod(){
        //业务相关代码
    }
}
public class ConcreteTemplate extends AbstractTemplate {
    //基本方法实现
    @Override
    protected void abstractMethod() {
        //业务相关代码
    }
    //重写父类方法
    @Override
    protected void hookMethod() {
        //业务相关代码
    }
}

访问者模式

封装一些施加于某种数据结构元素之上的操作。
|- 分派的概念:根据对象的类型而对方法进行的选择。

静态分派

发生在编译时期,分派根据静态类型信息发生。静态分派对于我们来说并不陌生,方法重载就是静态分派。
(墨子骑马的故事作为例子,墨子可以骑白马或者黑马):

image.png

运行结果如下:
骑马
骑马
注:但是两次对ride()方法的调用传入的是不同的参数,也就是wh和bh。它们虽然具有不同的真实类型,但是它们的静态类型都是一样的,均是Horse类型。
|- 由此可见重载方法的分派是根据静态类型进行的,这个分派过程在编译时期就完成了。

动态分派

发生在运行时期,动态分派动态地置换掉某个方法。
例:

image.png

运行结果如下:
黑马吃草
因此,对比可知:问题的核心就是Java编译器在编译时期并不总是知道哪些代码会被执行。
|- 编译器仅仅知道对象的静态类型,而不知道对象的真实类型。
|- 方法的调用则是根据对象的真实类型,而不是静态类型。
这样一来,上面最后一行的eat()方法调用的是BlackHorse类的eat()方法,打印的是“黑马吃草”。


本文转载自微信公众号【java学习之道】。

原文链接:https://mp.weixin.qq.com/s?__biz=MzU4NzYwNDAwMg==&mid=2247484049&idx=1&sn=dfa046909efd4671fc5167ff11beeb82&chksm=fde8cbdcca9f42cabe4138e5f116ec8f6f1b43170ad5c50f392fa0e44a56dd1271361cd0e2e4&scene=0#rd

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。