|
一、 職責鏈(Chain of Responsibility)模式 責任鏈模式是一種對象的行為模式【GOF95】。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞, 直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新 組織鏈和分配責任。 從擊鼓傳花談起 擊鼓傳花是一種熱鬧而又緊張的飲酒游戲。在酒宴上賓客依次坐定位置,由一人擊鼓,擊鼓的地方與傳花的地方是分開的,以示公正。開始擊鼓時,花束就開始依次傳遞,鼓聲一落,如果花束在某人手中,則該人就得飲酒。 擊鼓傳花便是責任鏈模式的應用。責任鏈可能是一條直線、一個環鏈或者一個樹結構的一部分。 二、 責任鏈模式的結構 責任鏈模式涉及到的角色如下所示:  抽象處理者(Handler)角色:定義出一個處理請求的接口。如果需要,接口可以定義出一個方法,以設定和返回對下家的引用。這個角色通常由一個抽象類或接口實現。 具體處理者(ConcreteHandler)角色:具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由于具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。 三、 責任鏈模式的示意性源代碼 // Chain of Responsibility pattern -- Structural example
using System;

// "Handler"
abstract class Handler
{
// Fields
protected Handler successor;
// Methods
public void SetSuccessor( Handler successor )
{
this.successor = successor;
}
abstract public void HandleRequest( int request );
}

// "ConcreteHandler1"
class ConcreteHandler1 : Handler
{
// Methods
override public void HandleRequest( int request )
{
if( request >= 0 && request < 10 )
Console.WriteLine("{0} handled request {1}",
this, request );
else
if( successor != null )
successor.HandleRequest( request );
}
}

// "ConcreteHandler2"
class ConcreteHandler2 : Handler
{
// Methods
override public void HandleRequest( int request )
{
if( request >= 10 && request < 20 )
Console.WriteLine("{0} handled request {1}",
this, request );
else
if( successor != null )
successor.HandleRequest( request );
}
}

// "ConcreteHandler3"
class ConcreteHandler3 : Handler
{
// Methods
override public void HandleRequest( int request )
{
if( request >= 20 && request < 30 )
Console.WriteLine("{0} handled request {1}",
this, request );
else
if( successor != null )
successor.HandleRequest( request );
}
}

/// <summary>
/// Client test
/// </summary> public class Client
{
public static void Main( string[] args )
{
// Setup Chain of Responsibility
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);

// Generate and process request
int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };

foreach( int request in requests )
h1.HandleRequest( request );

}
} 四、 純的與不純的責任鏈模式 一個純的責任鏈模式要求一個具體的處理者對象只能在兩個行為中選擇一個:一個是承擔責任,二是把責任推給下家。不允許出現某一個具體處理者對象在承擔了一部分責任后又把責任向下傳的情況。 在一個純的責任鏈模式里面,一個請求必須被某一個處理者對象所接收;在一個不純的責任鏈模式里面,一個請求可以最終不被任何接收端對象所接收。純的責任鏈模式的例子是不容易找到的,一般看到的例子均是不純的責任鏈模式的實現。 五、 責任鏈模式的實際應用案例 下面的責任鏈模式代碼演示了不同職務的人根據所設定的權限對一個購買請求作出決策或將其交給更高的決策者。 // Chain of Responsibility pattern -- Real World example
using System;

// "Handler"
abstract class Approver
{
// Fields
protected string name;
protected Approver successor;

// Constructors
public Approver( string name )
{
this.name = name;
}

// Methods
public void SetSuccessor( Approver successor )
{
this.successor = successor;
}

abstract public void ProcessRequest( PurchaseRequest request );
}

// "ConcreteHandler"
class Director : Approver
{
// Constructors
public Director ( string name ) : base( name ) {}

// Methods
override public void ProcessRequest( PurchaseRequest request )
{
if( request.Amount < 10000.0 )
Console.WriteLine( "{0} {1} approved request# {2}",
this, name, request.Number);
else
if( successor != null )
successor.ProcessRequest( request );
}
}

// "ConcreteHandler"
class VicePresident : Approver
{
// Constructors
public VicePresident ( string name ) : base( name ) {}

// Methods
override public void ProcessRequest( PurchaseRequest request )
{
if( request.Amount < 25000.0 )
Console.WriteLine( "{0} {1} approved request# {2}",
this, name, request.Number);
else
if( successor != null )
successor.ProcessRequest( request );
}
}

// "ConcreteHandler"
class President : Approver
{
// Constructors
public President ( string name ) : base( name ) {}
// Methods
override public void ProcessRequest( PurchaseRequest request )
{
if( request.Amount < 100000.0 )
Console.WriteLine( "{0} {1} approved request# {2}",
this, name, request.Number);
else
Console.WriteLine( "Request# {0} requires " +
"an executive meeting!", request.Number );
}
}

// Request details
class PurchaseRequest
{
// Member Fields
private int number;
private double amount;
private string purpose;

// Constructors
public PurchaseRequest( int number,
double amount, string purpose )
{
this.number = number;
this.amount = amount;
this.purpose = purpose;
}

// Properties
public double Amount
{
get{ return amount; }
set{ amount = value; }
}

public string Purpose
{
get{ return purpose; }
set{ purpose = value; }
}

public int Number
{
get{ return number; }
set{ number = value; }
}
}

/// <summary>
/// ChainApp Application
/// </summary> public class ChainApp
{
public static void Main( string[] args )
{
// Setup Chain of Responsibility
Director Larry = new Director( "Larry" );
VicePresident Sam = new VicePresident( "Sam" );
President Tammy = new President( "Tammy" );
Larry.SetSuccessor( Sam );
Sam.SetSuccessor( Tammy );

// Generate and process different requests
PurchaseRequest rs = new PurchaseRequest( 2034, 350.00, "Supplies" );
Larry.ProcessRequest( rs );

PurchaseRequest rx = new PurchaseRequest( 2035, 32590.10, "Project X" );
Larry.ProcessRequest( rx );

PurchaseRequest ry = new PurchaseRequest( 2036, 122100.00, "Project Y" );
Larry.ProcessRequest( ry );
}
} 六、 責任鏈模式的實現 責任鏈模式并不創建責任鏈。責任鏈的創建必須由系統的其它部分創建出來。 責任鏈模式降低了請求的發送端和接收端之間的耦合,使多個對象都有機會處理這個請求。一個鏈可以是一條線,一個樹,也可以是一個環。如下圖所示,責任鏈是一個樹結構的一部分。 
|