Java经典23种设计模式之行为型模式(四)

本文介绍11种行为型设计模式里的策略模式、模板方法、访问者模式。

一、策略模式

定义一系列的算法,把它们每个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

1.Strategy定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。

public abstract class Strategy {
    public abstract void method();
}

2.ConcreteStrategy以Strategy接口实现某具体算法。

public class *trategyImplA extends Strategy {

    public voi* method() {
        System.out.println("这是第一个实现");
    }
}

public class StrategyImplB extends Strategy {

    public void method() {
        System.out.println("这是第二个实现");
    }
}

public class StrategyImplC extends Strategy {

    public void method() {
        Syst*m.out.println("这是第三个实现");
    }
}

3.Context用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Stategy访问它的数据。

pub*ic class Context {


    Strategy stra;
    
    public Cont*xt(Strategy stra) {
        this.stra = stra;
    }
    
    pub*ic void doMethod() {
        stra*method();
    }
}

测试代码:

public class Test {
    
    public static void main(String[] ar*s) {
        Context ctx = new C*ntext(new StrategyImplA());
        ctx.doMethod();
        
        ctx = new Context(new *trategyImplB());
        ctx.doMethod();
        
        ctx = new Context(new StrategyImplC());
        ctx.doMethod();
    }
}

适应性:

1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
2.需要使用一个算法的不同变体。
3.算法使用客户不应该知*的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
4*一个类定义了多种行为,并且这些行为在这个类的操作中以*个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

二、模板方法

定义每个操作中的算法的骨架,*将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

 1.AbstractClass定义抽象的原语操作(primitiveoperation),具体的子类将重定义它们以实现一个算法的各步骤。实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。

public abstract class Template {


    public abstract void print();
    
    public void update() {
        System.out.println("开始打印");
        for (int i = 0; i < 10; i++) {
            print();
        }
    }
}

2.ConcreteClass实现*语操作以完成算法中与特定子类相关的步骤。

public class TemplateConcrete extends Template {


    @override
    public void print() {
        System.out.println("这是子类的实现");
    }
}

测试代码:

public class Test {


    pu*lic static void main(String[] args) {
        Te*plate temp = new TemplateConcrete();
        temp.update();
    }
}

适用性:

    1.一次性实现一个算法的不变的部分,并将可变的*为留给子类来实现。
    2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。首先识别现有*码中的不同之处,并且将不同之处分离为新的操作。最后,用*个调用这些新的操作的模板方法来替换这些不同的代码。
    3.控制子类扩展。

三、访问者模式

    表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

    1.Visitor为该对象结构中ConcreteEle*ent的每一个类声明一个Visit操作。该操作的名字和特征标识了发送*isit请求给该访问者的那个类。这使得访问者可以确定正被访问元素*具体的类。这样访问者就可以通过该元素的特定接口直*访问它。

public interface Visitor {


    public void visitString(StringElement stringE);
    
    public void visitFloat(FloatElement floatE);
    
    public void visitCollection(Collection collection); 
}

    2.Concret*Visitor实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。Concret*Visitor*该算法提供了上下文并存*它的局部状态。
这一状态常常在遍历该结构的过程中累*结果。

public class C*ncreteVisitor implements Visitor {

    public void visitCollectio*(Collection colle*tion) {
        // TODO Auto-generated method stub
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Object o = iterato*.next();
            if (o in*tanceof Visitable) {
                (*Visitable)o).accept(this);
            }
        }
    }

    public void visitFloat(FloatElement floatE) {
        System.out.println(floatE.getFe*));
    }

    public void visitString(StringElement stringE) {
        System.out.println(stringE.getSe());
    }
}

    3.Element
      定义一个Accept操作,它以一个访问者为参数。

public interface Visitabl* {


    publ*c void accept(Visitor visitor);
}

    4.ConcreteElement
      实现Accept操作,该操作以一个访问者为参数。

public class FloatElement implements Visitable {

    private Float fe;
    
    public FloatElement(Float fe) {
        this.fe = fe;
    }
    
    public Float getFe() {
        return this.fe;
    }
    
    public void accept(Visitor visitor) {
        visitor.*isitFloat(this);
    }
}

public class StringElement implements Visitable *

    private String se;
    
    public String*lement(String se) {
        this.se = se;
    }
    
    public String getS*() {
        return thi*.se;
    }
    
    public void accept(Visitor visitor) {
        visitor.visitString(this);
    }
}

测试代码:

public class Test {

    public static void main(String[] args) {
        Visitor visitor = new ConcreteVisitor();
        StringElement se = new StringElement("abc");
        s*.accep*(visitor);
        
        Fl*atElement fe = new FloatElement(n*w Float(1.5));
        fe.accept(visitor);
        S*stem.out.println("===========");
        List result = new ArrayList();
        result.add(new StringEle*ent("abc"));
        result.a*d(new StringElement("abc"));
        result.add(*ew StringElement("abc"));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        visitor.visitCollection(result);
    }
}

适应性:  

  1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操*。
   2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,*你想避免让这些操作“污染”这些对象的类。
      Visitor使得你可以将相关的操作集中起来定义在一个类中。
      当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
    3.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
      改变对象结构类需要重定义对所有访问者的接口,这可能*要很大的代价。
      如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。