2006年05月23日

设计模式—-设计模式总结(完)

 

 

从《设计模式精解》的学习开始到Visitor模式的学习结束,我的设计模式的学习历程就结束了,这段历程持续了好几个月简直就是蜗牛在爬J。设计模式就好像张无忌的“九阳神功”一样,威力是十分强大的。他将面向对象的概念和特征表现得凌厉尽致。对程序员的“内功修为”是大有益处的,正像专家们说的那样,学习设计模式绝对不是在浪费你的时间。这一点我深有体会。

 

 

我的设计模式学习分了两个部分。其实,主要是以两本书为主,第一本是《设计模式精解》这是一本非常奇妙的好书,作者用非常通俗易懂的语言对GoF的《设计模式》一书中的10个模式进行了讲解,可以说是这本书把我领上了设计模式的学习之路,真的很感谢这本非常易懂的好书,要不然我可能到现在都没有去学习设计模式。学习第二本书就是GoF的《设计模式》,当我学完了《设计模式精解》后,我对面向对象的理解自我感觉是上了一个层次。原因是我能够看懂GoF的《设计模式》了,这个时候我才真正认识到GoF的《设计模式》为什么被那么多人称道,为什么是设计模式的开山之作。每当我在GoF的《设计模式》中看懂一个模式的时候,我都非常自我庆幸,非常的欣欣然。体会在了模式的奥妙之中,那种感觉真的非常好。

 

 

GoF的《设计模式》中共讲解归纳了23种模式。并将这些模式分成了创建型模式、结构型模式、行为型模式。具体的哪个模式属于那种类型,我在这里就不说了书上一目了然。在这里我要说的是GoF的《设计模式》毕竟是1995年的东西了,毕竟年代久远了。当GoF归纳出设计模式后,后来的人是非常对其重视的。每个人在对其进行通俗解释的时候,对模式的类型和模式的个数又有所扩展。当我开始学习设计模式的时候,各家的说法都已经很成熟了,好像设计模式的热乎劲已经过去了。晚就晚吧,晚学比不学要好你说呢J

 

 

在整个的学习过程中我的参考资料有以下几种:

l         《设计模式精解》

l         《设计模式-可复用面向对象软件的基础》

l         板桥里人归纳解释的设计模式。说实在的非常不错,在他的网站上免费供人浏览。

l         Thinking in Patterns》不用我说,你应该知道是谁写的书了吧。

l         其他一些网友的Blog。太多了,这里就不罗列了。

l         Java与模式》,这本书是后来才看到的,因为太贵没有买后来在网上偶然下来的。有人对这本书非常称赞,有人对这本书骂骂咧咧,我想称赞的人应该是看了这本书的。谩骂得人可能有两种,一种是水平非常高的,看不起这本书;另一种是根本就没看过这本书的。我觉得以后者居多数。

 

 

到此我对设计模式有了个大概得了解,大约知道某个模式有什么样的功能,适用于那个场景。以后在实际的工作中就要多加思考了,碰到能用某个模式的时候要好好去理解和运用了。我的文笔实在太差了,好多东西想写但是写不出来,这个总结也就写到这里吧。至此,“九阳神功”第一层:模式了解修炼完毕。

设计模式—-Visitor(访问者)模式

 

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

 

处理多种类型之间的交互可能会使陈程序变得相当杂乱。比如,在一个数学表达式的系统中,我们需要支持a+ba-ba*ba/b这里的ab是一系列数字对象。但是,当我们仅仅给出a+b,我们并不知道ab的确切类型,那我们又如何让他们正确的交互呢?

 

Java中只能做单次分派(single dispatching)。也就是说,如果对于多于一个的类型位置的对象进行操作,Java只能对这些类型中的一种类型启用动态邦定机制。这并不能解决上面的问题,最后还是要自己动手写出侦测类型的代码,并且产生自己的动态邦定行为。这种方案叫做“多重分派”,多态只能通过成员函数调用来实现,所以如果想实现双重分派就必须要有两次成员函数调用:第一次调用决定第一个未知类型,第二次调用决定第二个未知类型。对于多重分派,你必须得有一个可供调用的多态方法来决定所有类型。通常,你可以通过设置配置项来实现用一个成员函数调用产生多于一个的动态成员函数调用,从而在这个过程中决定多于一种的类型。(关于多重分派,我还不是很理解。请参看《Java与模式》)

 

Visitor模式是多重分派的一种。Visitor模式适用于数据结构相对未定的系统,他把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由演化。

你手头有一组早先的类体系(class hierachy),这些类都是固定不能改变的;可能它们是从第三方买来的,所以你没法改变这个类体系。但是,你可能想给这个类体系添加新的多态方法,通常情况下这必须得向基类接口添加新的东西。所以问题就来了:你既需要给基类添加新的方法,而你又不能动基类。那到底该怎么办呢?解决这类问题就需要Visitor模式了。

Visitor模式使得你可以通过创建另外一个独立的visitor类型的类体系来扩展原始类型的接口,从而仿真(virtualize)实现原本针对原始类型的操作。原始类型的对象只是简单的接受访问者,然后调用访问者动态绑定的成员函数

 

下面给出示例代码:

在示例代码中主要由两个类继承体系来起到关键作用。

package Visitor;

 

public abstract class Visitor

{

    public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);

    public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);

}//end abstract class Visitor

 

package Visitor;

 

public class ConcreteVisitor1 extends Visitor

{

    public void visitConcreteElementA(ConcreteElementA cea)

    {

        System.out.println(cea);

        System.out.println(this);

    }//end visitConcreteElementA(…)

   

    public void visitConcreteElementB(ConcreteElementB ceb)

    {

        System.out.println(ceb);

        System.out.println(this);

    }//end visitConcreteElementB(…)

   

}//end class ConcreteVisitor1

 

package Visitor;

 

public class ConcreteVisitor2 extends Visitor

{

    public void visitConcreteElementA(ConcreteElementA cea)

    {

        System.out.println(cea);

        System.out.println(this);

    }//end visitConcreteElementA(…)

   

    public void visitConcreteElementB(ConcreteElementB ceb)

    {

        System.out.println(ceb);

        System.out.println(this);

    }//end visitConcreteElementB(…)

   

}//end class ConcreteVisitor1

 

package Visitor;

 

public abstract class Element

{

    public abstract void accept( Visitor visitor );

}//end abstract class Element

 

package Visitor;

 

public class ConcreteElementA extends Element

{

    public void accept(Visitor visitor)

    {

        visitor.visitConcreteElementA(this);

    }//end accept(…)

   

    public void operationA()

    {

        System.out.println("This is ConcreteElementA");

    }

   

}//end class ConcreteElementA

 

package Visitor;

 

public class ConcreteElementB extends Element

{

    public void accept(Visitor visitor)

    {

        visitor.visitConcreteElementB(this);

    }//end accept(…)

   

    public void operationB()

    {

        System.out.println("This is ConcreteElementB");

    }//end operationB()

   

}//end class ConcreteElementB

 

package Visitor;

 

import java.util.ArrayList;

import java.util.Iterator;

 

public class ObjectStructure

{

    private ArrayList elements = new ArrayList();

   

    public void attach(Element ele)

    {

        elements.add(ele);

    }//end attach(…)

   

    public void detach(Element ele)

    {

        elements.remove(ele);

    }//end detach(…)

   

    public void accept(Visitor visitor)

    {

        for(int i = 0; i < elements.size(); ++i)

        {

            Element elem = (Element)elements.remove(i);

            elem.accept(visitor);

        }

    }//end accept(…)

   

}//end class ObjectStructure

 

看看调用:

package Visitor;

 

public class VisitorPattern

{

    ObjectStructure os = new ObjectStructure();

    ConcreteVisitor1 cv1 = new ConcreteVisitor1();

    ConcreteVisitor2 cv2 = new ConcreteVisitor2();

   

    public VisitorPattern()

    {

        //do something….

    }

   

    public void showVisitorPattern()

    {

        os.attach(new ConcreteElementA());

        os.attach(new ConcreteElementB());

        os.accept(cv1);

        os.accept(cv2);

    }//end showVisitorPattern()

   

    public static void main(String[] args)

    {

        StringBuilder spp = new StringBuilder("The visitor pattern!");

        System.out.println(spp.toString());

        VisitorPattern vp = new VisitorPattern();

        vp.showVisitorPattern();

    }//end main(…)

   

}//end class VisitorPattern

 

下面给出Visitor模式的结构图:


 

在学习Visitor模式的时候学到了“多重分派”,和“单次分派”的概念。这是非常重要的概念。“多重分派”可以解决好多复杂的问题。其实现在的工作中就碰到了类似需要使用“多重分派”来解决的问题,只不过解决问题的工具不是Java而是一个类似汇编的语言。但是“多重分派”给了点启示。其实,到现在我还是不理解“多重分派”的意思。在夸张点我连Visitor模式也还是不理解。只是做了个大概的了解。还请高手多多指点!!!

 

参考文献:

1.《Thinking in Patterns

2.《Java与模式》

设计模式—-State(状态)模式

 

GoF允许一个对象在其内部状态改变时,改变他的行为。对象看起来似乎修改了它的类。

 

在实际的程序开发中,我们经常会用到大量的if elseif else对某种状态进行切换,特别是用惯了结构化语言(C语言)的人。如果状态切换的情况反复出现,我们就可以考虑到采用State模式来代替程序中大量的if elseif else了。在大多数情况下,如果对象的属性不同那么相应得对象的行为要求也不同。对GoF给出的定义做个通俗的解释就是:一个对象在不同的状态下有不同的行为,也可以说对象的每个状态有着不同的行为。

 

下面给出事例代码(我的这个事例比较简单,但是能反映出State模式的意思):

先来一个状态:

package State;

 

public abstract class State

{

   

    /** Creates a new instance of State */

    public State() {

    }

   

    public abstract void opration();

}//end class State

 

在来两个具体的State

package State;

 

public class ConcreteStateA extends State

{

   

    /** Creates a new instance of ConcreteStateA */

    public ConcreteStateA() {

    }

 

    public void opration()

    {

        System.out.println("The Concrete A");

    }//end opration()

   

    public static ConcreteStateA getInstance()

    {

        return new ConcreteStateA();

    }//end getInstance()

}

 

package State;

 

public class ConcreteStateB extends State

{

   

    /** Creates a new instance of ConcreteStateB */

    public ConcreteStateB() {

    }

 

    public void opration()

    {

        System.out.println("The Concrete B");

    }//end operation()

   

    public static ConcreteStateB getInstance()

    {

        return new ConcreteStateB();

    }//end getInstance()

   

}//end class ConcreteStateB

 

来一个场景:

package State;

 

public class Context

{

    private State state;

    /** Creates a new instance of Context */

    public Context() {

    }

   

    public void setSate(State stat)

    {

        state = stat;

    }//end setState(…)

   

    public void operation()

    {

        state.opration();

    }//end operation()

   

}//end class Context

 

怎样调用:

package State;

 

public class StatePattern

{

    State csa;

    Context con = new Context();

   

    /** Creates a new instance of StatePattern */

    public StatePattern()

    {

        csa = ConcreteStateA.getInstance();

    }

   

    public void showStatePattern()

    {

        con.setSate(csa);

        con.operation();

        csa = ConcreteStateB.getInstance();

        con.setSate(csa);

        con.operation();

    }//end showStatePattern()

   

    public static void main(String[] args)

    {

        StringBuilder ssb = new StringBuilder();

        ssb.append("The state pattern!");

        System.out.println(ssb.toString());

        StatePattern sp = new StatePattern();

        sp.showStatePattern();

    }//end main(…)

   

}//end class StatePattern

 

下面是UML图:


 

小结:

State模式和Strategy模式非常的相像,如果不仔细追究,差别不是很大。如果用不好的话很容易将State模式退化成Strategy模式。

 

设计模式—-Memento(备忘录)模式

 

GoF在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

 

Memento模式是用一个Memento对象来存储另外一个对象的内部状态(前提条件是不破坏封装),将一个对象的状态捕捉住,并外部化存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代器模式一同使用。

 

Memento模式中三个角色都很关键:

Memento(备忘录):备忘录存储原发器的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态;防止 原发器以外的其他对象访问备忘录。

Originator(原发器):创建一个备忘录,用以记录当前时刻他的内部状态;使用备忘录恢复内部状态。

Caretaker(负责人):负责保存好备忘录。不能对备忘录的内容进行操作或检查。

 

下面给出一个事例代码(来自《Java与模式》):

package Memento;

 

public class Memento

{

    private String state;

    /** Creates a new instance of Memento */

    public Memento(String state)

    {

        this.state = state;

    }//end Memento(…)

   

    public String getState()

    {

        return state;

    }//end getState()

   

    public void setState(String state)

    {

        this.state = state;

    }//end setState(…)

   

}//end class Memento

 

package Memento;

 

public class Originator

{

    private String state;

    /** Creates a new instance of Originator */

    public Originator() {

    }//end Originator()

   

    public Memento createMemento()

    {

        return new Memento(state);

    }//end createMemento()

   

    public void restoreMemento(Memento memento)

    {

        state = memento.getState();

    }//end restoreMemento(…)

   

    public String getState()

    {

        return state;

    }//end getState()

   

    public void setState(String state)

    {

        this.state = state;

        System.out.println("Current state = " + this.state);

    }//end setState(…)

   

}

 

package Memento;

 

public class Caretaker

{

    private Memento memento;

   

    /** Creates a new instance of Caretaker */

    public Caretaker() {

    }//end Caretaker()

   

    public Memento retrieveMemento()

    {

        return memento;

    }//end retrieveMemento()

   

    public void saveMemento(Memento memento)

    {

        this.memento = memento;

    }//end saveMemento(…)

   

}//end class Caretaker

 

看看怎么调用:

package Memento;

 

public class MementoPattern

{

    private static Originator ori = new Originator();

    private static Caretaker car = new Caretaker();

   

    /** Creates a new instance of MementoPattern */

    public MementoPattern() {

    }//end MementoPattern()

   

    public void showMementoPattern()

    {

        ori.setState("On");

        car.saveMemento(ori.createMemento());

        ori.setState("Off");

        ori.restoreMemento(car.retrieveMemento());

    }//end showMementoPattern()

   

    public static void main(String[] args)

    {

        StringBuilder ssb = new StringBuilder();

        ssb.append("The Memento Pattern!");

        System.out.println(ssb.toString());

        MementoPattern mp = new MementoPattern();

        mp.showMementoPattern();

    }//end main(…)

   

}//end class MementoPattern

 

给出Memento模式的UML图:


 

小结:

Memento模式还是比较好理解的,在GoF的《设计模式》和《Java与模式》中都讲了比较详细的内容。特别是在《Java与模式》中讲了Memento模式的变种,目前只是学习了解起概念和具体应用就可以了。深入的内容等碰到合适的场景在去理解和运用。

 

 

设计模式—-Mediator(中介者)模式

 

GoF用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地互相引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。

 

OOD鼓励奖行为封装到各个对象中,也就是将变化点封装。但是有时候这种封装可能会导致对象间有许多连接。极端情况下,每个对象都知道其他所有对象。各个对象之间的交互比较多,每个对象的行为操作都依赖其他对象。修改一个对象的行为,很可能同时涉及到修改很多其他对象的行为。那么这时,可以使用Mediator模式将集体行为封装在一个“中介者”对象中以避免这个问题。使用Mediator模式可以使各个对象间的耦合松散,只要关心每个对象和Mediator的关系,这样使多对多的关系变成了一对多的关系,每个对象都和Mediator联系。降低了系统得复杂性,提高了可扩展性和可修改性。

 

下面是实例代码:

package Mediator;

 

public abstract class Mediator

{

    public abstract void register(Colleague c, String type);

    public abstract void changed(String type);

}//end class Mediator

 

package Mediator;

 

public class ConcreteMediator extends Mediator

{

    private ColleagueA a;

    private ColleagueB b;

    private ColleagueC c;

 

    public ConcreteMediator()

    {

        //do something….

    }//end ConcreteMediator()

   

    public void register(Colleague colleague, String str)

    {

        if(str.equals("A")) {

                a = (ColleagueA)colleague;

        } else if (str.equals("B")) {

                b = (ColleagueB)colleague;

        } else if (str.equals("C")) {

                c = (ColleagueC)colleague;

        }

    }//end register(…)

   

    public void changed(String type)

    {

        if(type.equals("A")) {

                b.action();

                c.action();

        } else if (type.equals("B")) {

                a.action();

                c.action();

        } else if (type.equals("C")) {

                a.action();

                b.action();

        }

    }//end change(…)

   

}//end class changed(…)

 

package Mediator;

 

public abstract class Colleague

{

    public abstract void change();

    public abstract void action();

}//end class Colleague

 

package Mediator;

 

public class ColleagueA extends Colleague

{

    private final String type = "A";

    private Mediator med;

   

    public ColleagueA(Mediator m)

    {

        med = m;

        med.register(this, type);

    }//end ColleagueA(…)

   

    public void change()

    {

        System.out.println("———- A changed now ! ———-");

        med.changed(type);

    }//end change()

   

    public void action()

    {

        System.out.println("  A is changed by mediator ");

    }//end action()

   

}//end class Colleague

 

package Mediator;

 

public class ColleagueB extends Colleague

{

    private final String type = "B";

    private Mediator med;

   

    public ColleagueB(Mediator m)

    {

        med = m;

        med.register(this, type);

    }//end ColleagueB(…)

   

    public void change()

    {

        System.out.println("—–  B changed now !  —–");

        med.changed(type);

    }//end change()

   

    public void action()

    {

        System.out.println("  B is changed by mediator ");

    }//end action()

   

}//end class ColleagueB

 

package Mediator;

 

public class ColleagueC extends Colleague

{

    private final String type = "C";

    private Mediator med;

   

    public ColleagueC(Mediator m)

    {

        med = m;

        med.register(this, type);

    }//end ColleagueC(…)

   

    public void change()

    {

        System.out.println("—–  C changed now !  —–");

        med.changed(type);

    }//end change()

   

    public void action()

    {

        System.out.println("  C is changed by mediator ");

    }//end action()

   

}//end class ColleagueC

 

/*

 * MediatorPattern.java

 *

 * Created on 200654, 下午3:47

 *

 * To change this template, choose Tools | Template Manager

 * and open the template in the editor.

 */

 

package Mediator;

 

/**

 *

 * @author Administrator

 */

public class MediatorPattern

{

    Mediator myMed = new ConcreteMediator();

    ColleagueA ca = new ColleagueA(myMed);

    ColleagueB cb = new ColleagueB(myMed);

    ColleagueC cc = new ColleagueC(myMed);

   

    /** Creates a new instance of MediatorPattern */

    public MediatorPattern()

    {

        //do something….

    }//end MediatorPattern()

   

    public void showMediatorPattern()

    {

        ca.change();

        cb.change();

        cc.change();

    }//end showMediatorPattern()

   

    public static void main(String[] args)

    {

        StringBuilder strb = new StringBuilder("The Mediator Pattern!");

        System.out.println(strb.toString());

        MediatorPattern mp = new MediatorPattern();

        mp.showMediatorPattern();

    }//end main()

   

}//end class MediatorPattern

 

下面是UML图:


 

Mediator模式看的有些快,基本概念和意思搞明白了。结合实际经验以前还没有碰到过适合用Mediator模式的场景。以后也尽量避免多类多对象之间的相互操作。

 

设计模式—-Iterator(迭代器)模式

 

GoF提供一种方法顺序访问一个局和对象中各个元素,而又不需要暴露该对象的内部表示。

 

我们在学习数据结构的时候,在实现链表(list)时都会提供各种遍历链表的方法。对于一个聚合对象,比如说JavaArrayList也应该提供一种方法来让别人可以访问他的元素,而又不暴露他的内部结构。此外,针对不同的需要,可能要以不同的方式遍历这个表。

 

GOF的定义可以看出,迭代器是为容器而产生的。很显然,对容器(或)集合对象的访问设计到很多的遍历算法。在JavaIterator模式已经被融合到Collection中,随着JDK的不断升级,Iterator模式在Java集合中的能力越来越强。在绝大多数情况下,我们不需要自己制造一个Iterator,只要将将对象装入Collection中,直接用Iterator进行遍历就可以了。

 

这种应用太多了,在本章中就不再举例子了,下面给出结构图(出自GOF《设计模式》)


 

 

 

 

设计模式—-Interpreter(解释器)模式

 

 

GOF给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

现在的大大小小(以面的宽广来说)编程语言不下几百种。Interpreter模式描述了一个语言解释器是如何构成的,在实际应用中我们可能很少去构造一个语言的文法。因为现有的也学不好啊。考虑再三,我觉定不深入研究了。以后有时间再补上,有机会了再深入研究。为了设计模式学习的完整,还是写了这片文章。

下面给出两个连接,大家可以去看看人家高手是怎么实现的。

跬步致远——Ai92

http://blog.csdn.net/ai92/archive/2005/01/08/245363.aspx

板桥里人:

http://www.jdon.com/designpatterns/interpreter.htm

 

 

设计模式—-Command(命令)模式

 

GoF将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数华;对请求排队或记录请求日志,以及支持克撤销的操作。

 

在网上查找Command模式的相关资料,大多都是关于用户界面的。可能和GOF的先入为主有关系。在GoF的书中,四位作者举了个文本编辑器的例子。Command模式通过将请求本身变成一个对象来使工具箱对象可向未指定的应用对象提出请求。这个对象可被存储并像其他对象一样被传递。记得以前在《设计模式精解》的读书笔记中学习了几条经验,其中一条是:注意封装变化点。在Command模式中就是对变化点的典型封装。在Command模式中有一个关键的抽象类,一般人们命名为Command类。他定义了一个执行操作的接口。它有一个抽象的execute操作。具体的Command子类(继承自Command的具体类)将接收者(Receiver类)作为其一个事例变量,并实现execute操作,指定接收者采取的动作。而接收者有执行该请求所需要的具体信息。

 

下面举个例子:

先定义关键的Command抽象类(这里也可以用接口):

package Command;

 

public abstract class Command

{

    protected Receiver receiver;

 

    public Command(Receiver receiver)

    {

        this.receiver = receiver;

    }//end Command(…)

 

    abstract public void execute();

   

}//end abstract class Command

 

再继承一个具体类:

package Command;

 

public class ConcreteCommand extends Command

{

   

    public ConcreteCommand( Receiver receiver )

    {

        super(receiver);

    }//end ConcreteCommand(…)

 

    public void execute()

    {

        receiver.action();

    }//end execute()

 

}//end class ConcreteCommand

 

定义一个Receiver类:

package Command;

 

public class Receiver

{

    public void action()

    {

        System.out.println("Receiver.Action()");

    }//end Action()

   

}//end class Receiver

 

定义一个Invoker类:

package Command;

 

class Invoker

{

    private Command command;

 

    public void setCommand( Command command )

    {

        this.command = command;

    }//end setCommand(…)

 

    public void executeCommand()

    {

        command.execute();

    }//end executeCommand()

   

}//end class Invoker

 

最后是调用:

package Command;

 

public class CommandPattern

{

    Receiver rceiver = new Receiver();

    Command command = new ConcreteCommand(rceiver);

    Invoker invoker = new Invoker();

 

    /** Creates a new instance of CommandPattern */

    public CommandPattern()

    {

       

    }//end CommandPattern

   

    public void showCommandPattern()

    {

        invoker.setCommand(command);

        invoker.executeCommand();

    }//end showCommandPattern()

   

    public static void main(String[] args)

    {

        System.out.println("———————-");

        System.out.println("The Command Pattern!");

        CommandPattern cp = new CommandPattern();

        cp.showCommandPattern();

        System.out.println("———————-");

    }//end main(…)

   

}//end class CommandPattern

 

下面给出UML图,看一下他们之间的关系:


 

关于Command模式的知识在GoF的书里还介绍了好多,在我所做过的项目中一直也没有用到过Command模式所以在这里也就不多说了,详细的还是参考GOF的书吧。

 

参考文献:

《设计模式》 by GOF

Tinking In Pattern

板桥里人:http://www.jdon.com/designpatterns/command.htm

 

设计模式—-Chain of Responsibility(职责链)模式

 

GOF使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

 

Chain of Responsibility(职责链)模式其实也挺简单的。通俗的来说就是当一个请求发到我这里,我能处理就给处理,不能处理就推给其他人去处理。也就是说接受请求的对象形成一个链,请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户可以在不影响客户端的情况下动态的重新组织链和分配责任。也可以这样理解,你到一个地方去办一件事情,本来很小的事情,但是办事的人互相推诿扯皮,一个推一个,最后有个心善的人把事情给你办了。

 

下面是一个简单的例子:

 

package ChainOfResponsibility;

 

public abstract class Handler

{

    protected Handler successor;

   

    public void setSuccessor(Handler successor)

    {

        this.successor = successor;

    }//end setSuccessor(…)

   

    abstract public void handleRequest(int request);

 

}//end abstract class Handler

 

package ChainOfResponsibility;

 

public class ConcreteHandler1 extends Handler

{

    public void handleRequest(int request)

    {

        if(request >= 0 && request < 10){

            System.out.println(this);

            System.out.println("handled request " + request);

        }else{

            if(successor != null)

                successor.handleRequest(request);

        }

    }//end handleRequest(…)

   

}//End class ConcreteHandler1

 

package ChainOfResponsibility;

 

public class ConcreteHandler2 extends Handler

{

    public void handleRequest(int request)

    {

        if(request >= 10 && request < 20){

            System.out.println(this);

            System.out.println("handled request " + request);

        }else{

            if(successor != null)

                successor.handleRequest(request);

        }

    }//end handleRequest(…)

   

}//end class ConcreteHandler2

 

package ChainOfResponsibility;

 

public class ConcreteHandler3 extends Handler

{

    public void handleRequest(int request)

    {

        if(request >= 20 && request < 30){

            System.out.println(this);

            System.out.println("handled request " + request);

        }else{

            if(successor != null)

                successor.handleRequest(request);

        }

    }//end handleRequest(…)

}//end class ConcreteHandler3

 

下面是调用:

package ChainOfResponsibility;

 

public class ChainOfResponsibilityPattern

{

    Handler h1 = new ConcreteHandler1();

    Handler h2 = new ConcreteHandler2();

    Handler h3 = new ConcreteHandler3();

   

    public ChainOfResponsibilityPattern()

    {

        //do something….

    }//end ChainOfResponsibilityPattern()

   

    public void showChainOfResponsibilityPattern()

    {

        h1.setSuccessor(h2);

        h2.setSuccessor(h3);

        int[] request = {2, 5, 14, 22, 18, 3, 27, 20};

        for(int i = 0; i<request.length; ++i)

            h1.handleRequest(request[i]);

    }//end showChainOfResponsibilityPattern()

   

    public static void main(String[] args)

    {

        System.out.println("—————–");

        System.out.println("The Chain Of Responsibility Pattern!");

        ChainOfResponsibilityPattern corp = new ChainOfResponsibilityPattern();

        corp.showChainOfResponsibilityPattern();

        System.out.println("—————–");

    }//end main(…)

   

}//End Class ChainOfResponsibilityPattern

 

下面是UML图:


 

参考文献:

GOF《设计模式》 by GOF

Think in Patterns by Bruce Eckel

《设计模式》 by 板桥里人

http://zhenyulu.cnblogs.com/articles/65850.html

2006年05月16日

设计模式—-Proxy(代理)模式

 

GOF为其他对象提供一种代理以控制对这个对象的访问。

 

Flyweight不一样Proxy本身就是代理的意思。对一个对象进行访问控制的原因是,当我们确实需要这个对象,或者这个对象的某些功能后才去使用它。在一个论坛系统中(比如说非常著名的“天涯社区”)来说,浏览该论坛的有两种基本用户,一种是注册用户:可以发表文章,修改自己发表的文章,删除自己的文章,回复别人的文章等。另一种是游客(非注册用户):只有看文章的权限。在这样的系统中就可以用Proxy模式来代理控制这样两种用户的权限。

 

根据我在各种参考资料上看到的内容,Proxy模式还有许多变种,他适用于很多地方。在GOF的书中,阐述了如下使用Proxy模式的情景:

1.  远程代理(Remote Proxy):为一个对象在不同地址空间提供局部代表。

2.  虚代理(Virtua Proxy):根据需要创建开销很大的对象。比如说,在网站上看图片,一般都先显示小图片,想看大图片的时候可以点击小图片。

3.  保护代理(Protection Proxy):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。例如我们上面提到的论坛系统。

4.  智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。他的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放他(也称为Smart Pointers。这个好像在C++中有专门的讲解);当第一次引用一个持久对象时,将他装入内存;在访问一个实际对象前,检查是否已经锁定了他,以确保其他对象不能改变他。

 

举一个简单的例子来说明Proxy模式。在娱乐圈里明星要演出,要做广告这些事情都不是明星自己和商家谈,而是有一个自己的经济人,这个经济人就代理这个明星的一切外事活动。比如说和某某电影公司签约阿,或者和某厂家签约广告啊什么的。这个经济人就是个代理的脚色,他和商家谈判的时候觉得可行就让明星去演出或去拍广告,如果谈判不行他就取消该商家和该明星的联系活动,一定程度上来说他控制者明星的活动。

 

下面看简单的代码:

package Proxy;

 

public abstract class MusicPerson

{

    public abstract void age();

    public abstract void requital();//报酬

    public abstract void date();

}//end class MusicPerson

 

明星出场:

package Proxy;

 

public class MusicStar extends MusicPerson

{

    public void date()

    {

        System.out.println("the music person’s date");

    }//end f()

   

    public void requital()

    {

        System.out.println("the music person’s retuital");

    }//end g()

   

    public void age()

    {

        System.out.println("the musicperson’s age");

    }//end h()

   

}//end class MusicStar

 

代理人来了:

package Proxy;

 

public class MusicStarProxy extends MusicPerson

{

    private MusicPerson implementation;

   

    public MusicStarProxy()

    {

        implementation = new MusicStar();

    }

 

    public void date()

    {

        implementation.date();

    }//end date()

   

    public void requital()

    {

        implementation.requital();

    }//end requital()

   

    public void age()

    {

//        implementation.age();

        System.out.println("Sorry I can’t tell you the musicstar’s age!");

    }//end age()

   

}//end class MusicStarProxy

 

Porxy模式的运用:

package Proxy;

 

public class ProxyPattern

{

    private MusicPerson p = new MusicStarProxy();

   

    public void showProxyPattern()

    {

        p.date();

        p.requital();

        p.age();

    }//end showProxyPattern()

   

    public static void main(String[] args)

    {

        System.out.println("—————————-");

        System.out.println("The Proxy Pattern");

        ProxyPattern pp = new ProxyPattern();

        pp.showProxyPattern();

        System.out.println("—————————-");

    }//end main(…)

   

}//end class ProxyPattern

 

下面是Proxy模式的UML图:


Porxy模式给我的感觉是比较简单,简单的原因可能是我没有理解好,其他相关的变种也没有去看,等待以后有机会,有时间再去研究。