软件构造的设计模式中又两个很重要又长得很像的一对模式:decorater和visitor,编写程序和复习的时候遇到了相关问题,在此记录,希望能帮到你。
decorater,即装饰器模式,简单的来说,为了防止拓展功能只用子类的继承关系会造成组合爆炸,用委派机制将对象增加的不同的侧面的特性交给另一个ADT来做,而基本功能委派给自己。
举例:对于已经实现的名为ParkingField的ADT,用于模拟一个无人管理停车场,我想在它基础上拓展一个功能:给停车场交付一个公司名字,以及车辆在进入时能打印输出:“HELLO”,这些功能是新的,按照继承思维,应该建立一个子类,在子类中添加丰富功能和属性。但在Decorater中,我们不这样做。简单来说,步骤如下:
1.新建一个抽象类,用于实现需要装饰的ADT接口,这个类被称作装饰类。比如新建ParkingFieldDecorator实现ParkingField抽象接口,并且内部含有一个ConcreParkingField(即所要装饰的ADT的实现类)的对象,这一点很重要。
2.在装饰类中,“重写的方法不重写”,而是调用内部的ConcreParkingField来实现。这样,旧的ADT的基本功能就被委派给了已经有的基本ADT。
3.新建CompanyParkingField类,用于继承装饰类,具体实现丰富的内容。比如在其中加入String CompanyName用于存储公司信息。然后重要的地方来了:构造方法内,传递基础ADT以及新加入的变量,例如public CompanyParkingField(ParkingField pf,String CompanyName)
4.在装饰类的子类中,继续丰富想要的方法。
这样,原有功能被基本ADT直接调用,丰富的功能被装饰器的实现类揽下!
为什么说Visitor模式和Decorater模式相像?原因在于,已经完成的基本功能都不变化,新增功能都委派给外部另一个ADT间接完成。
那么现在来看Visitor模式:
这个模式相当于你搭起来一座房屋,但是预料到可能以后某一面墙会装窗户,所以那面墙的窗户那部分,你用了木板没用转头。等到要装窗户的时候,木板一拆,窗户一装就好了。不用拆墙,即不损坏原来已实现的ADT,而且知道哪里要插入修改。
简单来说,步骤如下:
1.新建访问器接口Visitor,里面仅有一个方法,名字叫visit,接受的参数是被修饰的ADT(给房子适配一个窗户框架)(在这里,最能体现访问者的含义,他把整个被修饰的ADT全盘接受,然后借用被访问者的方法,在外面丰富被访问者)
2.新建访问器实现类ConcreteVisitor,实现第一步里面的具体方法(给窗户框架上玻璃、花纹)
3.在被修饰接口中加入accept方法,接收参数是访问器类型(Visior)(给房子预留窗户)
4.在被装饰类的实现类中,填充accept方法,并且在里面直接调用Visitor,完成丰富的方法(装窗户)
这样,想要被添加的方法绕了一圈,实际上没有在自己本身上作修改,而是给外部的一个ADT(Visitor)完成了这样的事情。