美文网首页
Java设计模式之-策略模式(Strategy)

Java设计模式之-策略模式(Strategy)

作者: Mock2052 | 来源:发表于2017-12-11 21:39 被阅读0次

    这个模式,怎么说呢,听名字真的很唬人,但是实际上,就是简单地用一个接口进行方法的抽象......
    但是关键是这个模式想要传达的思想:
    在制定策略时,将策略的具体实现与调用者解耦,且策略间可灵活互换。
    我们还是来看一下设计模式一书是怎么描述策略模式的意图的:

    Define a family of algorithms, encapsulate each one, and make theminterchangeable. Strategy lets the algorithm vary independently fromclients that use it.

    所以策略模式要解决的是一个思维上的抽象过程,而非提出一个具体的且灵性的解决方案(solution)。


    策略模式

    大家看这个类图其实很简单,三个类实现一个接口,调用者使用接口中定义的方法。

    关于策略模式其实没有特殊的需要说明的,但是它可以被用来进行除了上一篇模板方法模式提到的之外,另一种钩子方法的实现方式。

    我们在Context中需要定义一个Strategy的变量,但是试想我们将变量的具体类放在调用时再确定,这个时候我们应该如何实例化strategy呢?这个时候我们需要一个空对象(Null Object)

    //Null Object
    public class NullStrategy{
        public void strategyInterface(){
            //do nothing...
        }
    }
    

    而在Context里的实现中,我们用NullStrategy来实例化strategy:

    public class Context{
        private Strategy strategy = new NullStrategy();
        public Context(){}
        public void contextInterface(){
            strategy.strategyInterface();
        }
    
        public void setStrategy(Strategy s){
            this.strategy = s;
        }
    }
    

    由于有了setStrategy这个方法,我们可以将最终确定实现策略的子类确定时间延后到使用时刻。

    public static void main(String[] args){
        Context context = new Context();
        context.contextInterface(); //do nothing...
        context.setStrategy(new ConcreteStrategyB());
        context.contextInterface(); //do ConcreteStrategyB.strategyInterface()
    }
    

    而这个setStrategy则成为了我们在代码中留出的一个钩子,增强了类的灵活性。
    另外在类中使用一个不做任何事的子类来进行实例化,其实也算是一种设计模式,只不过没有在GoF的书中提到。


    附:Null Object模式

    在设计实现中,很多地方都用到了Null Object设计模式。 Null Object提供了“什么也不做”的行为,隐藏来自它的合作者的细节。对于如何理解和应用该模式,通过一个实例就能很好的进行说明。这一节我们在讨论消息分派器,消息分派器使用了前述的日志记录器,并且通过属性来注入具体的日志记录器对象。

    private ILogger logger;
    public void setLogger(ILogger value){
        this.logger = value;
    }
    

    现在假设,我们在消息分派器内部的多个地方使用日志记录器来进行日志记录,我们总要写这样的语句:

    if (logger != null){
        logger.Log(); //记录日志
    }
    

    也就是说,在使用之前,我们都要判断一下日志记录器的引用是否为空,如果不为空才可以调用其Log方法。如果调用日志记录器进行日志记录的地方很多,那么每个地方都会充斥着这种判断其引用是否为空的代码。有没有办法来避免这所有的判断语句了,有!那就是使用Null Object设计模式。

    为每种必要的组件都提供了对应的Null Object类型,这些类型的名字以“Empty”作为前缀。比如ILogger对应的Null Object类型就是EmptyLogger,EmptyLogger实现的Log方法什么也不用做:

    public void Log(string errorType ,string msg, string location, ErrorLevel level){
        //Do Nothing !
    }
    

    有了EmptyLogger,我们就可以象这样来设计消息分派器的日志记录器属性:

    private ILogger logger = new EmptyLogger();
    
    public void setLogger(ILogger value){
        if (value != null){
            logger = value;
        }
    }
    

    如此一来,在消息分配器内部,我们就可以非常方便的直接使用日志记录器,而不用再判断其引用是否为空,因为无论如何,它总是指向一个有效的对象,即使这个对象是Null Object。

    相关文章

      网友评论

          本文标题:Java设计模式之-策略模式(Strategy)

          本文链接:https://www.haomeiwen.com/subject/kdpwixtx.html