策略模式Strategy、装饰模式Decorator

老子叫甜甜 提交于 2019-12-02 10:10:46

策略模式Strategy 定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、可维护、可扩展。 策略算法对算法调度具有平等性,算法仅仅是一种性质相同而行为不同的处理,地位相同,可相互替换,算法之间没有依赖关系。

—抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
—具体策略角色:包装了相关的算法和行为。
—环境角色:持有一个策略类的引用,最终给客户端调用。

策略模式UML图示


应用场景:
1、 多个类只区别在表现行为不同(性质一样,但行为不同),可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现(动态)。
3、 对客户隐藏具体策略(算法)的实现细节(只公开一个功能,隐藏此功能实现的细节),彼此完全独立。

优点:
1、  提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
1、 因为  每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
解决方案:工厂方法 

策略模式之惑

谁来选用策略模式?有2种情况:调用者,调用者选择具体的策略算法 ,然后把这个策略算法设置给上下文(发工资示例);服务者,由上下文(服务器端)选择具体的策略算法(容错恢复示例)。 

策略模式扩展问题

针对调用策略模式的2种角色差异,对策略模式的扩展也不尽相同。

(1)对由调用者(客户端)调用的策略模式,具体的做法是:先写一个策略算法类来实现新的要求,然后在客户端使用的时候指定使用新的策略算法类就可以了。《参见:桥接模式(单纬度的)》

(2)对服务端调用的策略模式,以容错恢复为例,可以将Context使用工厂方法(Context里做的是策略选择,可以通过改造实现动态配置)。

===================================================================

装饰模式Decorator 

定义:在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。实用了用一个对象去包含另一个对象的目的,这样就允许用户动态的向一个对象中添加额外的功能,而且最重要的是,这2种对象是完全独立的,而且是同质的(继承……)。

特点:(1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以和真实对象相同的方式和装饰对象交互。(2) 装饰对象包含一个真实对象的引用(reference)(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

装饰模式:Decorator常被翻译成“装饰”,我觉得翻译成“油漆工”更形象,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称为Decoratee,这两个实体在Decorator模式中是必须的。

Decorator模式定义:

动态给一个对象添加一些额外的职责,就像在墙上刷油漆。使用Decorator模式相比用生成子类方式达到功能的扩展显得更加灵活。

为什么使用Decorator?

我们通常可以使用继承来实现功能的扩展,如果这些需要扩展的功能种类繁很繁多,那么必生成很多子类,增加系统的复杂性,同时,使用继承实现功能扩展,我们必须可预见这些扩展功能,这些功能是编译时就确定了,是静态的。

使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机,Decorator提供了“即插即用”的方法,在运行期间决定何时增加何种功能。

如何使用?

我们先建立一个接口:

public interface Work
{
    public void insert();
}

接口Work又一个具体实现:插入方形桩或圆形桩,这两个区别对Decorator是无所谓。我们以插入方形桩为例:

public class SquarePeg implements Works
{
    public void insert()
    {
        System.out.println("方形桩插入");
    }
}

现在有一个应用,需要在桩打入前,挖坑,在打入后,在桩上钉木板,这些额外功能是动态,可以随意增加调整修改。

那么我们使用Decorator模式,这里方形桩SquarePeg是decoratee,我们需要在decoratee上刷些漆,这些油漆就是那些额外的功能。

public class Decorator implements Work
{
    private Work work;

    public Decorator(Work work)
    {
        this.work = work;
    }

    public insert()
    {
        beforeInsert();
        work.insert();
        afterInsert();
    }

    public beforeInsert()
    {

    }

    public afterInsert()
    {

    }
}

装饰模式就这样出来,我们如何调用:

Work squarePeg  = new SequarePeg();
Work decorator = new Decorator(squarePeg);
decorator.insert()

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!