2010-11-02 73 views
2

單一職責原則說明,例如,Invoice類不應包含自行打印的代碼。打印應該分成不同的類別。在可擴展類層次結構中實現單一責任原則的技術/模式

但是假設你有Invoice類的軟件的不同層的層次結構:

namespace CoreLayer { 
    public class Invoice { 
     public virtual void Print() { 
      ... 
     } 
    } 
} 

namespace CustomizedLayer { 
    public class LaborInvoice : Invoice { 
     public override void Print() { 
      ... 
     } 
    } 

    public class AccountInvoice : Invoice { 
     public override void Print() { 
      ... 
     } 
    } 
} 

什麼技術或設計模式可用於分離出印刷reponsibility?

思路:

  • 與測試爲Invoice每個子類,並運行相應的印碼一個偉大的大if聲明一個單獨的類。這似乎是錯誤的。
  • 訪客模式。問題在於訪問者接口需要存在於核心層中,並且引用了定製層中的類。我希望能夠在修改Core層的Customized圖層中添加新的子類。

回答

1

您可能要考慮Acyclic Visitor (PDF)

+0

有趣的閱讀!該解決方案使用多繼承和dynamic_cast在C++中提供。我恰好在使用C#,但我想我仍然可以通過將抽象訪問類更改爲接口來使用它。 – 2010-11-03 00:18:16

+0

查看[這裏](http://codecrafter.blogspot.ca/2012/12/the-acyclic-visitor-pattern.html)爲C#示例。 – 2012-12-25 05:55:47

1

您確實需要子類別發票嗎?除了印刷以外,發票有什麼不同?如果沒有,有沒有需要有不同類型的Invoice,你只需要不同類型的InvoicePrinter傳遞給Invoice實例:

namespace CoreLayer 
{ 
    public class IInvoicePrinter 
    { 
     void Print(Invoice invoice); 
    } 

    public class Invoice 
    { 
    } 
} 

namespace CustomizedLayer 
{ 
    public class LaborInvoicePrinter : IInvoicePrinter 
    { 
     public void Print(Invoice invoice) 
     { 
      ... 
     } 
    } 

    public class AccountInvoicePrinter : IInvoicePrinter 
    { 
     public void Print(Invoice invoice) 
     { 
      ... 
     } 
    } 
} 

你應該有某種的IoC爲您提供適當的InvoicePrinter實例。

1

我認爲bellow解決方案對於C#很有用,它沒有外部參數if,據我所知,不推薦使用visitor模式。

public class InvoicePrinterManager 
{ 
    public void Print(AccountInvoice invoice) 
    { 
     AccountInvoicePrinter p1 = new AccountInvoicePrinter(invoice); 
     p1.print(); 
    } 

    public void Print(LaborInvoice invoice) 
    { 
     LaborInvoicePrinter p1 = new LaborInvoicePrinter(invoice); 
     p1.print(); 
    } 
} 

public class InvoicePrinter<T> where T : Invoice, new() 
{ 
    T instance; 

    public InvoicePrinter(T invoice) 
    { 
     if (invoice != null) 
     { 
      this.instance = invoice; 
     } 
     else 
      instance = new T(); 
    } 

    public virtual void Print() 
    { 
     /// Arrange objects as you want and print them. 
    } 
} 

public class AccountInvoicePrinter : InvoicePrinter<AccountInvoice> 
{ 
    public AccountInvoicePrinter(AccountInvoice invoice) 
     : base(invoice) 
    { 
    } 

    public override void Print() 
    { 
     /// todo 
    } 
} 

public class LaborInvoicePrinter : InvoicePrinter<LaborInvoice> 
{ 
    public LaborInvoicePrinter(LaborInvoice invoice) 
     : base(invoice) 
    { 
    } 
    public override void Print() 
    { 
     /// todo: use instance 
    } 
} 

public class Test 
{ 
    public void TestPrint() 
    { 
     LaborInvoice li = new LaborInvoice(); 
     InvoicePrintManager printerManager = new InvoicePrintManager(); 
     printerManager.Print(li); 
    } 
} 
+0

我不確定這有助於消除檢查發票的每個子類的if語句。如果我有要打印的發票對象,如何獲取適當的InvoicePrinter來打印它? – 2010-11-03 00:12:06

+0

當你知道呼叫者在哪裏時,如果你不需要額外的話,但是如果你不知道呼叫者,是的,你應該有經理,我不知道如何防止轉換和反思,我會考慮但是直到現在我還沒有找到任何好主意 – 2010-11-03 07:19:46

+0

@Joe Daley,我剛剛更新了我的答案,還有一些額外的物件可以刪除它。但我認爲應該是更好的方法。 – 2010-11-03 09:18:58