2009-09-16 50 views
2

在過去幾年中,我一直在處理類似問題的項目,這些問題始終會導致問題。我很好奇,如果有人知道經典的OOP(Java,C#,PHP5等)設計模式,可以優雅地處理這種情況。處理將相似實體分組在一起的設計模式

假設我們有一個現有的系統。除此之外,這個系統還有兩種類型的實體,每個實體都由一個單獨的類來建模。比方說,

  1. 客戶

  2. 的SalesRepresentative

由於歷史原因,既不是這些類的從同一個基類繼承或共享一個通用的接口。

我所看到的問題不可避免地會出現一個新特性,需要我們將客戶和SalesRepresentative視爲同一類型的對象。我見過的方式在過去,這是處理創建一個新的類,它包含兩個成員變量,然後每個方法上的對象不同,這取決於它被設置

//pseudo PHPish code 
class Participator 
{ 
    public $customer; 
    public $salesRepresentative; 

    public function __construct($object) 
    { 
     if(object is instance of Customer) 
     { 
      $this->customer = $object; 
     } 

     if(object is instance of SalesRepresentative) 
     { 
      $this->salesRepresentative = $object; 
     }   
    } 

    public function doesSomething() 
    { 

     if($customer) 
     { 
      //We're a customer, do customer specific stuff 
     } 
     else if($salesRepresentative) 
     { 
      //We're a salesRepresentative, do sales 
      //representative specific stuff 
     }   
    } 
} 

操作是否有處理這種情況的更優雅的方式?

回答

8

也許一個包裝可以在這裏使用。創建一個包裝接口,稱爲ParticipatorWrapper,它指定新功能併爲每個類構建具體的包裝器,比如說CustomerWrapper和SalesRepresentativeWrapper,它們都實現了新功能。

然後只需將對象包裝在適當的包裝器中,然後編寫以ParticipatorWrapper爲目標的代碼即可。

更新:Javaish代碼:

interface ParticipatorWrapper{ 
    public void doSomething(); 
} 

class CustomerWrapper implements ParticipatorWrapper{ 
    Customer customer; 
    public void doSomething(){ 
     //do something with the customer 
    } 
} 

class SaleREpresentativeWrapper implements ParticipatorWrapper{ 
    SaleRepresentative salesRepresentative; 
    public void doSomething(){ 
     //do something with the salesRepresentative 
    } 

} 

class ClientOfWrapper{ 
    public void mymethod(){ 
     ParticipatorWrapper p = new ParticipatorWrapper(new Customer()); 
     p.doSomething(); 
    } 
} 
+1

+1:適配器模式的很好例子。 – Adamski 2009-09-16 16:35:38

+0

+1與OP的建議類似的邏輯,但比每個方法中的if/else塊更容易閱讀和維護。如果直到運行時才知道類型,則可能與靜態工廠方法耦合。 – 2009-09-16 16:40:06

+0

+1 - 但您需要添加工廠以創建適當的ParticipatorWrapper,或者更改新的ParticipatorWrapper(新的Customer())行來創建CustomerWrapper。 – 2009-09-16 16:40:24

1

我想你可以的mixins概念應用到你的類得到你想要的功能。

2

這是文森特答案的另一種選擇,採取了相反的方法。正如我在下面指出的那樣,有一些缺點,但是您的具體問題可能會消除這些問題,我認爲這種解決方案在這些情況下更簡單(或者您可能希望使用此解決方案和Vincent的某種組合)。

不是包裝類,而是在類中引入鉤子,然後將函數傳遞給它們。這是一個合理的選擇,如果你想用兩個類的相同數據來做同樣的事情(我猜你是基於感嘆這兩個類沒有共享的超類)。

這是使用Visitor而不是Wrapper。Javaish這是喜歡的東西:

public <Output> Output visit(Vistor<Output> v) { 
return v.process(...all shared the fields in Customer/SalesRep...); 
} 

然後你有訪客界面,所有的功能,從繼承的樣子:

interface Visitor<Output> { 
public Output process(...shared fields...); 
} 

有someways砍什麼獲取傳遞給你的訪客,但涉及到引入新的類來指定使用哪些輸入,而這些輸入也會變成包裝,所以你不妨使用文森特的答案。

這個解決方案的缺點是如果你做了一些改變類字段結構的東西,你可以給自己買很多重構,這在文森特的答案中不是什麼問題。如果您要修改存儲在Customer/SalesRep實例中的數據,該解決方案的用處也不大,因爲您必須將這些數據包裝到Visitor中。

+1

哦,這也假定你可以對遺留類進行修改。我假設你不是因爲其他現存的依賴關係而重構,也不是因爲你不允許這樣做,這會阻礙我的解決方案。 – Carl 2009-09-16 20:22:45

+0

+1以獲得更好的信息,因爲我主要感興趣的是看到可以解決問題的各種設計模式。當你住在PHP的土地上時,你不會接觸到很多真實世界的例子。 – 2009-09-16 21:36:04