新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论Java, J2SE, J2ME, J2EE, 以及Eclipse, NetBeans, JBuilder等Java开发环境,还有JSP, JavaServlet, JavaBean, EJB以及struts, hibernate, spring, webwork2, Java 3D, JOGL等相关技术。
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 Java/Eclipse 』 → 设计模式之Interpreter(解释器) 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 15657 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 设计模式之Interpreter(解释器) 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客楼主
    发贴心情 设计模式之Interpreter(解释器)

    Interpreter解释器模式定义:
    定义语言的文法 ,并且建立一个解释器来解释该语言中的句子.

    Interpreter似乎使用面不是很广,它描述了一个语言解释器是如何构成的,在实际应用中,我们可能很少去构造一个语言的文法.我们还是来简单的了解一下:

    首先要建立一个接口,用来描述共同的操作.

    public interface AbstractExpression {
       void interpret( Context context );
    }

    再看看包含解释器之外的一些全局信息

    public interface Context { }

    AbstractExpression的具体实现分两种:终结符表达式和非终结符表达式:

    public class TerminalExpression implements AbstractExpression {
       public void interpret( Context context ) { }
    }

    对于文法中没一条规则,非终结符表达式都必须的:
    public class NonterminalExpression implements AbstractExpression {
       private AbstractExpression successor;
      
       public void setSuccessor( AbstractExpression successor ) {
         this.successor = successor;
       }

       public AbstractExpression getSuccessor() {
         return successor;
       }

       public void interpret( Context context ) { }
    }


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:00:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客2
    发贴心情 
    设计模式之Visitor
    Visitor访问者模式定义
    作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.

    在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为.

    为何使用Visitor?
    Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术,可是Collection好象是个黑色大染缸,本来有各种鲜明类型特征的对象一旦放入后,再取出时,这些类型就消失了.那么我们势必要用If来判断,如:


    Iterator iterator = collection.iterator()
    while (iterator.hasNext()) {
       Object o = iterator.next();
       if (o instanceof Collection)
          messyPrintCollection((Collection)o);
       else if (o instanceof String)
          System.out.println("'"+o.toString()+"'");
       else if (o instanceof Float)
          System.out.println(o.toString()+"f");
       else
          System.out.println(o.toString());
    }
    在上例中,我们使用了 instanceof来判断 o的类型.

    很显然,这样做的缺点代码If else if 很繁琐.我们就可以使用Visitor模式解决它.

    如何使用Visitor?
    针对上例,定义接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问性.

    被访问者是我们Collection的每个元素Element,我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的,只有访问者,被访问者如果表示不欢迎,访问者就不能访问),取名为Visitable,也可取名为Element。

    public interface Visitable
    {
       public void accept(Visitor visitor);
    }

    被访问的具体元素继承这个新的接口Visitable:

    public class StringElement implements Visitable
    {
       private String value;
       public StringElement(String string) {
          value = string;
       }

       public String getValue(){
          return value;
       }


       //定义accept的具体内容 这里是很简单的一句调用
       public void accept(Visitor visitor) {
          visitor.visitString(this);
       }
    }

    上面是被访问者是字符串类型,下面再建立一个Float类型的:

    public class FloatElement implements Visitable
    {
       private Float value;
       public FloatElement(Float value) {
          this.value = value;
       }

       public Float getValue(){
          return value;
       }


       //定义accept的具体内容 这里是很简单的一句调用
       public void accept(Visitor visitor) {
          visitor.visitFloat(this);
       }
    }

    我们设计一个接口visitor访问者,在这个接口中,有一些访问操作,这些访问操作是专门访问对象集合Collection中有可能的所有类,目前我们假定有三个行为:访问对象集合中的字符串类型;访问对象集合中的Float类型;访问对象集合中的对象集合类型。注意最后一个类型是集合嵌套,通过这个嵌套实现可以看出使用访问模式的一个优点。

    接口visitor访问者如下:

    public interface Visitor
    {

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

    }

    访问者的实现:

    public class ConcreteVisitor implements Visitor
    {
       //在本方法中,我们实现了对Collection的元素的成功访问
       public void visitCollection(Collection collection) {
          Iterator iterator = collection.iterator()
          while (iterator.hasNext()) {
             Object o = iterator.next();
             if (o instanceof Visitable)
                ((Visitable)o).accept(this);
          }
       }

       public void visitString(StringElement stringE) {
          System.out.println("'"+stringE.getValue()+"'");
       }
       public void visitFloat(FloatElement floatE){
          System.out.println(floatE.getValue().toString()+"f");
       }

    }

    在上面的visitCollection我们实现了对Collection每个元素访问,只使用了一个判断语句,只要判断其是否可以访问.

    StringElement只是一个实现,可以拓展为更多的实现,整个核心奥妙在accept方法中,在遍历Collection时,通过相应的accept方法调用具体类型的被访问者。这一步确定了被访问者类型,

    如果是StringElement,而StringElement则回调访问者的visiteString方法,这一步实现了行为操作方法。

    客户端代码:

    Visitor visitor = new ConcreteVisitor();

    StringElement stringE = new StringElement("I am a String");
    visitor.visitString(stringE);

    Collection list = new ArrayList();
    list.add(new StringElement("I am a String1"));
    list.add(new StringElement("I am a String2"));
    list.add(new FloatElement(new Float(12)));
    list.add(new StringElement("I am a String3"));
    visitor.visitCollection(list);

    客户端代码中的list对象集合中放置了多种数据类型,对对象集合中的访问不必象一开始那样,使用instance of逐个判断,而是通过访问者模式巧妙实现了。

    至此,我们完成了Visitor模式基本结构.

    使用Visitor模式的前提
    使用访问者模式是对象群结构中(Collection) 中的对象类型很少改变。

    在两个接口Visitor和Visitable中,确保Visitable很少变化,也就是说,确保不能老有新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.

    如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化,Visistable也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式。

    但是在Java中,Java的Reflect技术解决了这个问题,因此结合reflect反射机制,可以使得访问者模式适用范围更广了。

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:01:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客3
    发贴心情 
    设计模式之Mediator(中介者)
    Mediator中介者模式定义:
    用一个中介对象来封装一系列关于对象交互行为.

    为何使用Mediator?
    各个对象之间的交互操作非常多;每个对象的行为操作都依赖彼此对方,修改一个对象的行为,同时会涉及到修改很多其他对象的行为,如果使用Mediator模式,可以使各个对象间的耦合松散,只需关心和 Mediator的关系,使多对多的关系变成了一对多的关系,可以降低系统的复杂性,提高可修改扩展性.

    如何使用?

    首先 有一个接口,用来定义成员对象之间的交互联系方式:

    public interface Mediator { }

    Meiator具体实现,真正实现交互操作的内容:

    public class ConcreteMediator implements Mediator {

       //假设当前有两个成员.
       private ConcreteColleague1 colleague1 = new ConcreteColleague1();
       private ConcreteColleague2 colleague2 = new ConcreteColleague2();

       ...

    }

    再看看另外一个参与者:成员,因为是交互行为,都需要双方提供一些共同接口,这种要求在Visitor Observer等模式中都是相同的.

    public class Colleague {
       private Mediator mediator;
       public Mediator getMediator() {
          return mediator;
       }

       public void setMediator( Mediator mediator ) {
          this.mediator = mediator;
       }
    }

    public class ConcreteColleague1 { }

    public class ConcreteColleague2 { }

    每个成员都必须知道Mediator,并且和 Mediator联系,而不是和其他成员联系.

    至此,Mediator模式框架完成,可以发现Mediator模式规定不是很多,大体框架也比较简单,但实际使用起来就非常灵活.

    Mediator模式在事件驱动类应用中比较多,例如界面设计GUI.;聊天,消息传递等,在聊天应用中,需要有一个MessageMediator,专门负责request/reponse之间任务的调节.

    MVC是J2EE的一个基本模式,View Controller是一种Mediator,它是Jsp和服务器上应用程序间的Mediator.

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:01:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客4
    发贴心情 
    设计模式之Strategy(策略)
    Strategy策略模式是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类.

    Stratrgy应用比较广泛,比如, 公司经营业务变化图, 可能有两种实现方式,一个是线条曲线,一个是框图(bar),这是两种算法,可以使用Strategy实现.

    这里以字符串替代为例, 有一个文件,我们需要读取后,希望替代其中相应的变量,然后输出.关于替代其中变量的方法可能有多种方法,这取决于用户的要求,所以我们要准备几套变量字符替代方案.

    首先,我们建立一个抽象类RepTempRule 定义一些公用变量和方法:

    public abstract class RepTempRule{

    protected String oldString="";
    public void setOldString(String oldString){
      this.oldString=oldString;
    }

    protected String newString="";
    public String getNewString(){
      return newString;
    }

    public abstract void replace() throws Exception;


    }

    在RepTempRule中 有一个抽象方法abstract需要继承明确,这个replace里其实是替代的具体方法.
    我们现在有两个字符替代方案,
    1.将文本中aaa替代成bbb;
    2.将文本中aaa替代成ccc;

    对应的类分别是RepTempRuleOne RepTempRuleTwo

    public class RepTempRuleOne extends RepTempRule{


    public void replace() throws Exception{

      //replaceFirst是jdk1.4新特性
      newString=oldString.replaceFirst("aaa", "bbbb")
      System.out.println("this is replace one");
      
    }


    }

    public class RepTempRuleTwo extends RepTempRule{


    public void replace() throws Exception{

      newString=oldString.replaceFirst("aaa", "ccc")
      System.out.println("this is replace Two");
      
    }


    }

    第二步:我们要建立一个算法解决类,用来提供客户端可以自由选择算法。

    public class RepTempRuleSolve {
      private RepTempRule strategy;

      public RepTempRuleSolve(RepTempRule rule){
        this.strategy=rule;
      }

      public String getNewContext(Site site,String oldString) {
        return strategy.replace(site,oldString);
      }

      public void changeAlgorithm(RepTempRule newAlgorithm) {
        strategy = newAlgorithm;
      }

    }

    调用如下:

    public class test{

    ......

      public void testReplace(){

      //使用第一套替代方案
      RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple());
      solver.getNewContext(site,context);

      //使用第二套

      solver=new RepTempRuleSolve(new RepTempRuleTwo());
      solver.getNewContext(site,context);


      }

    .....

    }

    我们达到了在运行期间,可以自由切换算法的目的。

    实际整个Strategy的核心部分就是抽象类的使用,使用Strategy模式可以在用户需要变化时,修改量很少,而且快速.

    Strategy和Factory有一定的类似,Strategy相对简单容易理解,并且可以在运行时刻自由切换。Factory重点是用来创建对象。

    Strategy适合下列场合:

    1.以不同的格式保存文件;

    2.以不同的算法压缩文件;

    3.以不同的算法截获图象;

    4.以不同的格式输出同样数据的图形,比如曲线 或框图bar等

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:02:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客5
    发贴心情 
    设计模式之State

    State模式的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为.

    何时使用?
    State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了.

    不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State.


    是否使用?
    在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度.

    这里要阐述的是"开关切换状态" 和" 一般的状态判断"是有一些区别的, " 一般的状态判断"也是有 if..elseif结构,例如:

        if (which==1) state="hello";
        else if (which==2) state="hi";
        else if (which==3) state="bye";


    这是一个 " 一般的状态判断",state值的不同是根据which变量来决定的,which和state没有关系.如果改成:

        if (state.euqals("bye")) state="hello";
        else if (state.euqals("hello")) state="hi";
        else if (state.euqals("hi")) state="bye";


    这就是 "开关切换状态",是将state的状态从"hello"切换到"hi",再切换到""bye";在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了.

    如果单纯有上面一种将"hello"-->"hi"-->"bye"-->"hello"这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了.

    请看下例:

    public class Context{

      private Color state=null;

      public void push(){

        //如果当前red状态 就切换到blue
        if (state==Color.red) state=Color.blue;

        //如果当前blue状态 就切换到green
        else if (state==Color.blue) state=Color.green;

        //如果当前black状态 就切换到red
        else if (state==Color.black) state=Color.red;

        //如果当前green状态 就切换到black
        else if (state==Color.green) state=Color.black;
        
        Sample sample=new Sample(state);
        sample.operate();
      }

      public void pull(){

        //与push状态切换正好相反

        if (state==Color.green) state=Color.blue;
        else if (state==Color.black) state=Color.green;
        else if (state==Color.blue) state=Color.red;
        else if (state==Color.red) state=Color.black;

        Sample2 sample2=new Sample2(state);
        sample2.operate();
      }

    }

    在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它.

    另外注意:但就上例,state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此在,就本例,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂.

    例如: 银行帐户, 经常会在Open 状态和Close状态间转换.

    例如: 经典的TcpConnection, Tcp的状态有创建 侦听 关闭三个,并且反复转换,其创建 侦听 关闭的具体行为不是简单一两句就能完成的,适合使用State

    例如:信箱POP帐号, 会有四种状态, start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的.适合使用State

    例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State.如 具体绘图程序,用户可以选择不同工具绘制方框 直线 曲线,这种状态切换可以使用State.

    如何使用
    State需要两种类型实体参与:

    1.state manager 状态管理器 ,就是开关 ,如上面例子的Context实际就是一个state manager, 在state manager中有对状态的切换动作.
    2.用抽象类或接口实现的父类,,不同状态就是继承这个父类的不同子类.

    以上面的Context为例.我们要修改它,建立两个类型的实体.
    第一步: 首先建立一个父类:

    public abstract class State{

      public abstract void handlepush(Context c);
      public abstract void handlepull(Context c);
      public abstract void getcolor();

    }

    父类中的方法要对应state manager中的开关行为,在state manager中 本例就是Context中,有两个开关动作push推和pull拉.那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull(); 同时还需要一个获取push或pull结果的方法getcolor()

    下面是具体子类的实现:

    public class BlueState extends State{

      public void handlepush(Context c){
         //根据push方法"如果是blue状态的切换到green" ;
         c.setState(new GreenState());

      }
      public void handlepull(Context c){

         //根据pull方法"如果是blue状态的切换到red" ;
        c.setState(new RedState());

      }

      public abstract void getcolor(){ return (Color.blue)}

    }


    同样 其他状态的子类实现如blue一样.

    第二步: 要重新改写State manager 也就是本例的Context:

    public class Context{

      private Sate state=null; //我们将原来的 Color state 改成了新建的State state;

      //setState是用来改变state的状态 使用setState实现状态的切换
      pulic void setState(State state){

        this.state=state;

      }

      public void push(){

        //状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心
        state.handlepush(this);
        
        //因为sample要使用state中的一个切换结果,使用getColor()
        Sample sample=new Sample(state.getColor());
        sample.operate();

      }

      public void pull(){

        state.handlepull(this);
        
        Sample2 sample2=new Sample2(state.getColor());
        sample2.operate();

      }

    }


    至此,我们也就实现了State的refactorying过程.

    以上只是相当简单的一个实例,在实际应用中,handlepush或handelpull的处理是复杂的.

    状态模式优点:
    (1) 封装转换过程,也就是转换规则
    (2) 枚举可能的状态,因此,需要事先确定状态种类。


    状态模式可以允许客户端改变状态的转换行为,而状态机则是能够自动改变状态,状态机是一个比较独立的而且复杂的机制,具体可参考一个状态机开源项目:http://sourceforge.net/projects/smframework/

    状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如政府OA中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状态的使用者。

    在网络游戏中,一个游戏活动存在开始;开玩;正在玩;输赢等各种状态,使用状态模式就可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游戏架构功能实现起到决定的主导作用。

    状态模式实质:
    使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。

    使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如何状态变化,这些是由状态机等内部实现。

    这是一种Event-condition-State,状态模式封装了condition-State部分。

    每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。

    状态转换有几个方法实现:一个在每个状态实现next(),指定下一个状态;还有一种方法,设定一个StateOwner,在StateOwner设定stateEnter状态进入和stateExit状态退出行为。

    状态从一个方面说明了流程,流程是随时间而改变,状态是截取流程某个时间片。

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:02:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客6
    发贴心情 
    设计模式之Command
    Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体,规定很多的模式,正是这个灵活性,让人有些confuse.

    Command定义
    n 将来自客户端的请求传入一个对象,无需了解这个请求激活的 动作或有关接受这个请求的处理细节。

    这是一种两台机器之间通讯联系性质的模式,类似传统过程语 言的 CallBack功能。

    优点:
    解耦了发送者和接受者之间联系。 发送者调用一个操作,接受者接受请求执行相应的动作,因为使用Command模式解耦,发送者无需知道接受者任何接口。

    不少Command模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单选择一个命令时,然后会执行一些动作.

    将这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command模式,换句话说,本来用户(调用者)是直接调用这些命令的,如菜单上打开文档(调用者),就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了.

    显然这样做的好处是符合封装的特性,降低耦合度,Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式,
    从Command模式,我也发现设计模式一个"通病":好象喜欢将简单的问题复杂化, 喜欢在不同类中增加第三者,当然这样做有利于代码的健壮性 可维护性 还有复用性.

    如何使用?
    具体的Command模式代码各式各样,因为如何封装命令,不同系统,有不同的做法.下面事例是将命令封装在一个Collection的List中,任何对象一旦加入List中,实际上装入了一个封闭的黑盒中,对象的特性消失了,只有取出时,才有可能模糊的分辨出:

    典型的Command模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装为对象":
    public interface Command {
      public abstract void execute ( );
    }

    具体不同命令/请求代码是实现接口Command,下面有三个具体命令
    public class Engineer implements Command {

      public void execute( ) {
        //do Engineer's command
      }
    }
    public class Programmer implements Command {

      public void execute( ) {
        //do programmer's command
      }
    }

    public class Politician implements Command {

      public void execute( ) {
        //do Politician's command
      }
    }


    按照通常做法,我们就可以直接调用这三个Command,但是使用Command模式,我们要将他们封装起来,扔到黑盒子List里去:


    public class producer{
      public static List produceRequests() {
        List queue = new ArrayList();
        queue.add( new DomesticEngineer() );
        queue.add( new Politician() );
        queue.add( new Programmer() );
        return queue;
      }

    }

    这三个命令进入List中后,已经失去了其外表特征,以后再取出,也可能无法分辨出谁是Engineer 谁是Programmer了,看下面客户端如何调用Command模式:


    public class TestCommand {
      public static void main(String[] args) {
        
        List queue = Producer.produceRequests();
        for (Iterator it = queue.iterator(); it.hasNext(); )
          
     //客户端直接调用execute方法,无需知道被调用者的其它更多类的方法名。
            ((Command)it.next()).execute();
      

      }
    }

    由此可见,调用者基本只和接口打交道,不合具体实现交互,这也体现了一个原则,面向接口编程,这样,以后增加第四个具体命令时,就不必修改调用者TestCommand中的代码了.

    理解了上面的代码的核心原理,在使用中,就应该各人有自己方法了,特别是在如何分离调用者和具体命令上,有很多实现方法,上面的代码是使用"从List过一遍"的做法.这种做法只是为了演示.


    使用Command模式的一个好理由还因为它能实现Undo功能.每个具体命令都可以记住它刚刚执行的动作,并且在需要时恢复.

    Command模式在界面设计中应用广泛.Java的Swing中菜单命令都是使用Command模式,由于Java在界面设计的性能上还有欠缺,因此界面设计具体代码我们就不讨论,网络上有很多这样的示例.

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:03:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客7
    发贴心情 
    设计模式之Chain of Responsibility(职责链)
    Chain of Responsibility定义
    Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去。

    如何使用?
    虽然这一段是如何使用CoR,但是也是演示什么是CoR.

    有一个Handler接口:

    public interface Handler{
      public void handleRequest();
    }

    这是一个处理request的事例, 如果有多种request,比如 请求帮助 请求打印 或请求格式化:

    最先想到的解决方案是:在接口中增加多个请求:
    public interface Handler{
      public void handleHelp();
      public void handlePrint();
      public void handleFormat();

    }

    具体是一段实现接口Handler代码:
    public class ConcreteHandler implements Handler{
      private Handler successor;

      public ConcreteHandler(Handler successor){
      this.successor=successor;
    }

      public void handleHelp(){
        //具体处理请求Help的代码
        ...
      }

      public void handlePrint(){
        //如果是print 转去处理Print
        successor.handlePrint();
      }
      public void handleFormat(){
        //如果是Format 转去处理format
        successor.handleFormat();
      }

    }
    一共有三个这样的具体实现类,上面是处理help,还有处理Print 处理Format这大概是我们最常用的编程思路。

    虽然思路简单明了,但是有一个扩展问题,如果我们需要再增加一个请求request种类,需要修改接口及其每一个实现。

    第二方案:将每种request都变成一个接口,因此我们有以下代码 :

    public interface HelpHandler{
      public void handleHelp();
    }

    public interface PrintHandler{
      public void handlePrint();
    }

    public interface FormatHandler{
      public void handleFormat();
    }

    public class ConcreteHandler
      implements HelpHandler,PrintHandler,FormatHandlet{
      private HelpHandler helpSuccessor;
      private PrintHandler printSuccessor;
      private FormatHandler formatSuccessor;

      public ConcreteHandler(HelpHandler helpSuccessor,PrintHandler printSuccessor,FormatHandler             formatSuccessor)
      {
        this.helpSuccessor=helpSuccessor;
        this.printSuccessor=printSuccessor;
        this.formatSuccessor=formatSuccessor;
      }

      public void handleHelp(){
        .......
      }

      public void handlePrint(){this.printSuccessor=printSuccessor;}

      public void handleFormat(){this.formatSuccessor=formatSuccessor;}

    }

    这个办法在增加新的请求request情况下,只是节省了接口的修改量,接口实现ConcreteHandler还需要修改。而且代码显然不简单美丽。

    解决方案3: 在Handler接口中只使用一个参数化方法:
    public interface Handler{
      public void handleRequest(String request);
    }
    那么Handler实现代码如下:
    public class ConcreteHandler implements Handler{
      private Handler successor;

      public ConcreteHandler(Handler successor){
        this.successor=successor;
      }

      public void handleRequest(String request){
        if (request.equals("Help")){
          //这里是处理Help的具体代码
        }else
          //传递到下一个
          successor.handle(request);

        }
      }

    }


    这里先假设request是String类型,如果不是怎么办?当然我们可以创建一个专门类Request


    最后解决方案:接口Handler的代码如下:
    public interface Handler{
      public void handleRequest(Request request);
    }
    Request类的定义:
    public class Request{
      private String type;

      public Request(String type){this.type=type;}

      public String getType(){return type;}

      public void execute(){
        //request真正具体行为代码
      }
    }
    那么Handler实现代码如下:
    public class ConcreteHandler implements Handler{
      private Handler successor;

      public ConcreteHandler(Handler successor){
        this.successor=successor;
      }

      public void handleRequest(Request request){
        if (request instanceof HelpRequest){
          //这里是处理Help的具体代码
        }else if (request instanceof PrintRequst){
          request.execute();
        }else
          //传递到下一个
          successor.handle(request);

        }
      }

    }

    这个解决方案就是CoR, 在一个链上,都有相应职责的类,因此叫Chain of Responsibility.

    CoR的优点:
    因为无法预知来自外界(客户端)的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃就可以。

    缺点是效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念优化。 在Java AWT1.0中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1以后,就使用Observer代替CoR

    扩展性差,因为在CoR中,一定要有一个统一的接口Handler.局限性就在这里。

    与Command模式区别:

    Command 模式需要事先协商客户端和服务器端的调用关系,比如 1 代表 start 2 代表 move 等,这些 都是封装在 request 中,到达服务器端再分解。

    CoR 模式就无需这种事先约定,服务器端可以使用 CoR 模式进行客户端请求的猜测,一个个猜测 试验。

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:04:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客8
    发贴心情 
    设计模式之Observer
    Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本站所关注的是Java在电子商务系统中应用,因此想从电子商务实例中分析Observer的应用.

    虽然网上商店形式多样,每个站点有自己的特色,但也有其一般的共性,单就"商品的变化,以便及时通知订户"这一点,是很多网上商店共有的模式,这一模式类似Observer patern观察者模式.

    具体的说,如果网上商店中商品在名称 价格等方面有变化,如果系统能自动通知会员,将是网上商店区别传统商店的一大特色.这就需要在商品product中加入Observer这样角色,以便product细节发生变化时,Observer能自动观察到这种变化,并能进行及时的update或notify动作.

    Java的API还为为我们提供现成的Observer接口Java.util.Observer.我们只要直接使用它就可以.

    我们必须extends Java.util.Observer才能真正使用它:
    1.提供Add/Delete observer的方法;
    2.提供通知(notisfy) 所有observer的方法;


    //产品类 可供Jsp直接使用UseBean调用 该类主要执行产品数据库插入 更新
    public class product extends Observable{
      private String name;
      private float price;

      public String getName(){ return name;}
      public void setName(String name){
       this.name=name;
      //设置变化点
       setChanged();
       notifyObservers(name);

      }   

      public float getPrice(){ return price;}
      public void setPrice(float price){
       this.price=price;
      //设置变化点
       setChanged();
       notifyObservers(new Float(price));

      }

      //以下可以是数据库更新 插入命令.
      public void saveToDb(){
      .....................


    }


    我们注意到,在product类中 的setXXX方法中,我们设置了 notify(通知)方法, 当Jsp表单调用setXXX(如何调用见我的另外一篇文章),实际上就触发了notisfyObservers方法,这将通知相应观察者应该采取行动了.

    下面看看这些观察者的代码,他们究竟采取了什么行动:

    //观察者NameObserver主要用来对产品名称(name)进行观察的
    public class NameObserver implements Observer{

      private String name=null;

      public void update(Observable obj,Object arg){

        if (arg instanceof String){

         name=(String)arg;
         //产品名称改变值在name中
         System.out.println("NameObserver :name changet to "+name);

        }


      }

    }

    //观察者PriceObserver主要用来对产品价格(price)进行观察的
    public class PriceObserver implements Observer{

      private float price=0;

      public void update(Observable obj,Object arg){

        if (arg instanceof Float){

         price=((Float)arg).floatValue();
      
         System.out.println("PriceObserver :price changet to "+price);

        }


      }

    }


    Jsp中我们可以来正式执行这段观察者程序:

    <jsp:useBean id="product" scope="session" class="Product" />
    <jsp:setProperty name="product" property="*" />

    <jsp:useBean id="nameobs" scope="session" class="NameObserver" />
    <jsp:setProperty name="product" property="*" />

    <jsp:useBean id="priceobs" scope="session" class="PriceObserver" />
    <jsp:setProperty name="product" property="*" />

    <%

    if (request.getParameter("save")!=null)
    {
      product.saveToDb();


      out.println("产品数据变动 保存! 并已经自动通知客户");

    }else{

      //加入观察者
      product.addObserver(nameobs);

      product.addObserver(priceobs);

    %>

      //request.getRequestURI()是产生本jsp的程序名,就是自己调用自己
      <form action="<%=request.getRequestURI()%>" method=post>

      <input type=hidden name="save" value="1">
      产品名称:<input type=text name="name" >
      产品价格:<input type=text name="price">
      <input type=submit>

      </form>

    <%

    }

    %>


    执行改Jsp程序,会出现一个表单录入界面, 需要输入产品名称 产品价格, 点按Submit后,还是执行该jsp的
    if (request.getParameter("save")!=null)之间的代码.


    由于这里使用了数据javabeans的自动赋值概念,实际程序自动执行了setName setPrice语句.你会在服务器控制台中发现下面信息::

    NameObserver :name changet to ?????(Jsp表单中输入的产品名称)

    PriceObserver :price changet to ???(Jsp表单中输入的产品价格);

    这说明观察者已经在行动了.!!
    同时你会在执行jsp的浏览器端得到信息:

    产品数据变动 保存! 并已经自动通知客户

    上文由于使用jsp概念,隐含很多自动动作,现将调用观察者的Java代码写如下:

    public class Test {

      public static void main(String args[]){

    Product product=new Product();

    NameObserver nameobs=new NameObserver();
    PriceObserver priceobs=new PriceObserver();

    //加入观察者
    product.addObserver(nameobs);
    product.addObserver(priceobs);

    product.setName("橘子红了");
    product.setPrice(9.22f);

      }

    }


    你会在发现下面信息::

    NameObserver :name changet to 橘子红了

    PriceObserver :price changet to 9.22

    这说明观察者在行动了.!!

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:04:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客9
    发贴心情 
    设计模式之Memento(备忘机制)

    Memento备望录模式定义:
    memento是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原先保存的状态.

    Memento模式相对也比较好理解,我们看下列代码:

    public class Originator {

       private int number;
      private File file = null;

      public Originator(){}

      // 创建一个Memento
      public Memento getMemento(){
        return new Memento(this);
      }

      // 恢复到原始值
      public void setMemento(Memento m){
         number = m.number;
         file = m.file;
      }

    }


    我们再看看Memento类:

    private class Memento implements java.io.Serializable{

      private int number;

      private File file = null;

      public Memento( Originator o){

        number = o.number;
        file = o.file;

      }

    }

    可见 Memento中保存了Originator中的number和file的值. 通过调用Originator中number和file值改变的话,通过调用setMemento()方法可以恢复.

    Memento模式的缺点是耗费大,如果内部状态很多,再保存一份,无意要浪费大量内存.

    Memento模式在Jsp+Javabean中的应用
    在Jsp应用中,我们通常有很多表单要求用户输入,比如用户注册,需要输入姓名和Email等, 如果一些表项用户没有填写或者填写错误,我们希望在用户按"提交Submit"后,通过Jsp程序检查,发现确实有未填写项目,则在该项目下红字显示警告或错误,同时,还要显示用户刚才已经输入的表项.

    如下图中 First Name是用户已经输入,Last Name没有输入,我们则提示红字警告.:

    这种技术的实现,就是利用了Javabean的scope="request"或scope="session"特性,也就是Memento模式.

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:05:00
     
     npuhetao 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      头衔:骨灰级菜鸟
      等级:大二(研究C++)
      文章:230
      积分:2708
      门派:XML.ORG.CN
      注册:2004/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给npuhetao发送一个短消息 把npuhetao加入好友 查看npuhetao的个人资料 搜索npuhetao在『 Java/Eclipse 』的所有贴子 引用回复这个贴子 回复这个贴子 查看npuhetao的博客10
    发贴心情 
    设计模式之Template
    Template模板模式定义:
    定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中.

    使用Java的抽象类时,就经常会使用到Template模式,因此Template模式使用很普遍.而且很容易理解和使用。

    public abstract class Benchmark
    {
      /**
      * 下面操作是我们希望在子类中完成
      */
      public abstract void benchmark();
      /**
      * 重复执行benchmark次数
      */
      public final long repeat (int count) {
        if (count <= 0)
          return 0;
        else {
          long startTime = System.currentTimeMillis();

        for (int i = 0; i < count; i++)
          benchmark();

        long stopTime = System.currentTimeMillis();
        return stopTime - startTime;
      }
    }
    }

    在上例中,我们希望重复执行benchmark()操作,但是对benchmark()的具体内容没有说明,而是延迟到其子类中描述:

    public class MethodBenchmark extends Benchmark
    {
      /**
      * 真正定义benchmark内容
      */
      public void benchmark() {

        for (int i = 0; i < Integer.MAX_VALUE; i++){
          System.out.printtln("i="+i);    
        }
      }
    }

    至此,Template模式已经完成,是不是很简单?

    我们称repeat方法为模板方法, 它其中的benchmark()实现被延迟到子类MethodBenchmark中实现了,

    看看如何使用:

    Benchmark operation = new MethodBenchmark();
    long duration = operation.repeat(Integer.parseInt(args[0].trim()));
    System.out.println("The operation took " + duration + " milliseconds");

    也许你以前还疑惑抽象类有什么用,现在你应该彻底明白了吧? 至于这样做的好处,很显然啊,扩展性强,以后Benchmark内容变化,我只要再做一个继承子类就可以,不必修改其他应用代码.

    ----------------------------------------------
    你硬要把单纯的事情看得很严重,那样子你会很痛苦。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/3/15 10:05:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 Java/Eclipse 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/15 8:52:57

    本主题贴数18,分页: [1] [2]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    140.625ms