Wednesday, August 22, 2007

Java|Design Pattern|java设计模式之Chain of Responsibility

java设计模式之Chain of Responsibility - [Matrix - 与 Java 共舞]

java设计模式之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.局限性就在这里。

Tuesday, August 21, 2007

Java|Desgine Pattern|《设计模式》学习笔记--桥接Bridge

《设计模式》学习笔记--桥接Bridge - upyaya的Java专栏 - CSDNBlog

欢迎转载,请注明出处。

1、核心意图:

将抽象部分和实现部分分离,使它们都可以独立的变化。
该模式的目标是通过把高层的抽象和底层的实现分开,分别构建自己的类层次结构,并通过实现部分的接口将两部分进行桥接,从而达到高层抽象和底层实现可以独立的方便扩展的目的。其核心是分离,和委托。
 
2、身边实例:
Java语言的一个非常重要的特点是平台的无关性,对于一般的高级语言所编写的程序,如果要在不同的平台上运行,为了适应不同平台所带来的指令集及数据类型等所带来的差异,至少需要编译成不同的目标代码。
Java语言通过Java虚拟机实现了平台的无关性,虚拟机通过对底层平台指令集及数据类型等进行统一的抽象,针对不同的平台用不同的虚拟机进行实现,这样Java应用程序就可以通过编译成符合虚拟机规范的字节码文件,而在不同的平台上都能正确运行。
这里的虚拟机正是桥接模式一个很好的展示,它隔离了底层实现(指令/数据类型等)和高层的应用程序,对于新开发的每个Java应用程序,都只需要编译一次;而对于一个新平台的支持,也仅需提供一个相应的Java虚拟机,就可以使所有应用系统正确运行。
Java应用程序及虚拟机的大体结构图如下:
 
3、动机简述:
在该模式的动机中,描述了一个平台可移植的用户界面工具箱,在该工具箱中会有多种窗口Window类型,为了实现平台的可移植性,把窗口的实现部分从窗口类型中抽取出来,构成一个独立的窗口实现WindowImp类层次,从而使得抽象窗口和窗口实现都可以独立变化,以便于支持新的窗口类型和平台实现。
 
4、模式效果:
桥接Bridge模式有两个主要效果:1)通过分离抽象部分和实现部分,使两者可以独立变化;2)向客户隐藏了实现部分,从而当需要扩展/更改实现部分时,不需要重新编译客户代码。
对于效果1),当抽象部分和实现部分比较多样时,可以显著的减少类的种类,并提高代码的灵活性。假定高层抽象和底层实现分别有5种类型,如果不采用桥接模式,而用继承实现,那么就需要5*5=25个类(另有一个抽象类);如果采用桥接模式,将抽象部分和实现部分分离,就只需要5+5=10个类就可以(另有两个抽象类),两种实现的类如以下表格中所示:
 
继承方式实现:

 
Implementor
Imp1
Imp2
Imp3
Imp4
Imp5
Abstraction
Abs1
Abs1Imp1
Abs1Imp2
Abs1Imp3
Abs1Imp4
Abs1Imp5
Abs2
Abs2Imp1
Abs2Imp2
Abs2Imp3
Abs2Imp4
Abs2Imp5
Abs3
Abs3Imp1
Abs3Imp2
Abs3Imp3
Abs3Imp4
Abs3Imp5
Abs4
Abs4Imp1
Abs4Imp2
Abs4Imp3
Abs4Imp4
Abs4Imp5
Abs5
Abs5Imp1
Abs5Imp2
Abs5Imp3
Abs5Imp4
Abs5Imp5

 
桥接模式实现:

 
Implementor
Imp1
Imp2
Imp3
Imp4
Imp5
Abstraction
Abs1
通过桥接关联
Abs2
Abs3
Abs4
Abs5

 
5、Java代码示例:
下面代码演示了一个支持不同平台的图形对象应用,图形Shape有多种类型,如三角形正方形等,为了在不同平台中实现图形的绘制,把实现部分进行了分离,构成了ShapeImp类层次结构,包括在Windows中的ShapeImpWin,和Unix中的ShapeImpUnix,类结构图如下:
 
代码清单如下:
类Point,同上一篇文章 《设计模式》之Java解读--适配器Adapter中所示,表示画面中的一个点坐标
 
package qinysong.pattern.bridge;

public class Point  ...{

  
private int coordinateX;
  
private int coordinateY;

  
public Point(int coordinateX,  int coordinateY)... {
    
this .coordinateX = coordinateX;
    
this.coordinateY = coordinateY;
  }

  
public String toString() ...{
    
return "Point[x="  + coordinateX +  ",y=" +  coordinateY + "] ";
  }

  
public int getCoordinateX()  ...{
    
return coordinateX;
  }

  
public int getCoordinateY()  ...{
    
return coordinateY;
  }

}

 
类ShapeImp,实现接口(对应Implementor),这里只是画一条直线
 
package qinysong.pattern.bridge.implement ;

import qinysong.pattern.bridge.Point;

public interface ShapeImp  ...{
  
public void drawLine(Point startPoint, Point endPoint);
}

 
类ShapeImpWin,实现接口的Windows实现类(对应ConcreteImplementor)
 
package qinysong.pattern.bridge.implement ;

import qinysong.pattern.bridge.Point;

public class ShapeImpWin  implements ShapeImp ... {

  
/** *//**
   * 实现ShapeImp接口方法
   * 
@param startPoint Point
   * 
@param endPoint Point
   
*/

  
public void drawLine(Point startPoint, Point endPoint)  ...{
    System.out.println(
"ShapeImpWin.drawLine startPoint="  + startPoint +  ",endPoint=" +  endPoint);
  }

}

 
类ShapeImpUnix,实现接口的Unix实现类(对应ConcreteImplementor)
 
package qinysong.pattern.bridge.implement ;

import qinysong.pattern.bridge.Point;

public class ShapeImpUnix  implements ShapeImp ... {

  
/** *//**
   * 实现ShapeImp接口方法
   * 
@param startPoint Point
   * 
@param endPoint Point
   
*/

  
public void drawLine(Point startPoint, Point endPoint)  ...{
    System.out.println(
"ShapeImpUnix.drawLine startPoint="  + startPoint +  ",endPoint=" +  endPoint);
  }

}

 
类Shape,图形抽象类(对应Abstraction),具体类型包括三角形、正方形等
 
package qinysong.pattern.bridge.abstraction ;

import qinysong.pattern.bridge.implement.ShapeImp;
import qinysong.pattern.bridge.ShapeImpFactory;

public abstract  class Shape ... {

  
protected ShapeImp shapeImp;
  
protected void initShapeImp() ...{
    shapeImp 
= ShapeImpFactory.getShapeImp();
  }


  
//定义图形抽象类的接口方法
  public abstract  void drawShape();

}

 
类Triangle,三角形(对应RefinedAbstraction)
 
package qinysong.pattern.bridge.abstraction ;

import qinysong.pattern.bridge.Point;

public class Triangle  extends Shape... {

  
//实现抽象图形类Shape接口方法,绘制一个三角形
  public void  drawShape() ... {
    System.out.println(
" Triangle.drawShape 绘制一个三角形...");
    initShapeImp();
    shapeImp.drawLine(
new  Point(0,0),  new Point(10,0 ));
    shapeImp.drawLine(
new  Point(0,0),  new Point(5,10 ));
    shapeImp.drawLine(
new  Point(5,10),  new Point(10,0 ));
  }

}

 
类Square,正方形(对应RefinedAbstraction)
 
package qinysong.pattern.bridge.abstraction ;

import qinysong.pattern.bridge.Point;

public class Square  extends Shape... {

  
//实现抽象图形类Shape接口方法,绘制一个正方形
  public void  drawShape() ... {
    System.out.println(
" Square.drawShape 绘制一个正方形...");
    initShapeImp();
    shapeImp.drawLine(
new  Point(0,0),  new Point(10,0 ));
    shapeImp.drawLine(
new  Point(0,0),  new Point(0,10 ));
    shapeImp.drawLine(
new  Point(0,10),  new Point(10,10 ));
    shapeImp.drawLine(
new  Point(10,0),  new Point(10,10 ));
  }

}

 
类Client,桥接模式的客户
 
package qinysong.pattern.bridge;

import qinysong.pattern.bridge.abstraction.Shape;
import qinysong.pattern.bridge.abstraction.Square;
import qinysong.pattern.bridge.abstraction.Triangle;

public class Client  ...{

  
public static  void main(String[] args) ... {
    System.out.println(
" Client.main begin ..........");
    Shape shape 
= new Square();
    shape.drawShape();
    Shape shape2 
=  new Triangle();
    shape2.drawShape ();

     System.out.println(
"Client.main end   .........." );
  }

}

 
类ShapeImpFactory,工厂类,供抽象部分调用,分离实现类的创建过程
 
package qinysong.pattern.bridge;

import qinysong.pattern.bridge.implement.ShapeImp;
import qinysong.pattern.bridge.implement.ShapeImpWin;

public class ShapeImpFactory  ...{
  
public static ShapeImp getShapeImp() ...{
    
return new ShapeImpWin();
  }

}