2012-08-29 59 views
1

假設我正在編寫硬件附件的用戶界面。有兩種版本的配件 - 比如Widget Lite和Widget Pro。具有可擴展功能的用戶界面的設計模式

Widget Pro可以完成Widget Lite可以做的所有事情,但是還有其他幾個選項可以做Widget Lite不能做的一些事情。更詳細地說,Widget Lite有一個通道,Pro有兩個通道,所以當涉及類似於音量控制的事情時,我只需要Lite的一個控件,但是兩個Pro允許獨立控制。

在我第一次嘗試構建一個應用程序來處理這個問題時,我有了代表Widget Pro擴展Widget Lite的類,但後來我用各種有條件的情況來處理看起來很醜的區別。有沒有人知道一個合適的設計模式來幫助這種情況?在想出可能有助於我的搜索的同義詞的情況下,我的想象力正在空白。

+1

在您的示例中,LSP違規是至關重要的。如果您可以找到Lite不能用Pro取代的地方,則無法從Lite中派生Pro。 –

回答

0

如下我會做到這一點:

   AbstractWidget (Abstract class) 
        /\ 
       /\ 
       / \ 
       / \ 
      /  \ 
     WidgetLite WidgetPro 

通用代碼將進入AbstractWidget(抽象的,因爲,它不應該被實例化),這是這兩個類將進入之間的不同行爲具體的類。

0

我強烈建議你有一個Widget類,其中Widget LiteWidget Pro派生自。

public class Widget {} 

public class WidgetLite : Widget {} 

public class WidgetPro : Widget {} 

具有由兩個ProLite基類內共享的屬性/方法。這對你來說是一個更清潔的設計。

2

我會先看看plug in模式(依賴反轉的一種形式)。

嘗試並抽象Lite和Pro版本通用的接口,例如

interface IBaseWidget 
{ 
    IControl CreateVolumeControl(); 
    // ... etc 
} 

在單獨的組件/ DLL文件,實現您的精簡版和專業版小工具:

class LiteWidget : IBaseWidget 
{ 
    int _countCreated = 0; 
    IControl CreateVolumeControl() 
    { 
     _countCreated++; 
     if (_countCreated > 1) 
     { 
      throw new PleaseBuyTheProVersionException(); 
     } 
    } 
} 

既然你不想分配與精簡版部署Pro版本,您將需要加載動態鏈接庫在運行時,例如按照慣例(例如,您的基本應用程序查找DLL的名爲* Widget.dll),或者通過配置找到適用的IBaseWidget的具體實現。根據@ Bartek的評論,理想情況下,你不希望你的基礎引擎classfactory「知道」IBaseWidget的具體類。

+0

爲什麼會違反LSP(classfactory contra實現)? – jgauffin

+0

@jgauffin認爲這不是LSP的技術違規 – StuartLC

1

訪客模式可能對您有用。檢查dofactory

訪問者類...

...聲明一個訪問操作在 對象結構中的每個類ConcreteElement的。該操作的名稱和簽名標識將訪問請求發送給訪問者的類 。這讓 訪問者確定正在訪問的元素的具體類。 然後,遊客可以直接通過其 特定接口

這類似於抽象類實現訪問的元素通過Vikdor所講述。

Here是此鏈接的維基鏈接。

訪問者模式需要一種支持 單一調度和方法重載的編程語言。

我已經提供了一個非常簡單的實現,使用訪客模式來滿足您對WidgetLite和Pro的不同頻道和音量設置的需求。我在評論中提到訪問者模式將大大幫助您減少if-else調用。

基本的理念是您將控件(例如音量)傳遞給小部件,並且會根據需要知道如何使用它。因此,控制對象本身具有非常簡化的實現。每個部件的代碼保持在一起!

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace WidgetVisitor 
{ 
    //This is the widget interface. It ensures that each widget type 
    //implements a visit functionality for each control. The visit function 
    //is overloaded here. 
    //The appropriate method is called by checking the parameter and this 
    //avoids the if-then logic elegantly 
    public interface Widget 
    { 
     void visit(Volume vol); 
     void visit(Channel chan); 
     void Display(AllControls ac); 
    } 

    //This is the interface which defines the controls. Each control that 
    //inherits this interface needs to define an "accept" method which 
    //calls the appropriate visit function of the right visitor, 
    //with the right control parameter passed through its call! 
    //This is how the double dispatch works. 
    //Double dispatch: A mechanism that dispatches a function call to different concrete 
    //functions depending on the runtime types of two objects involved in the call. 
    public interface WidgetControls 
    { 
     void accept(Widget visitor); 

    } 

    //I have implemented the volume control and channel control 
    //Notice how the code for defining each control is the SAME 
    //in visitor pattern! This is double dispatch in action 
    public class Volume : WidgetControls 
    { 
     public int volLevel { get; set; } 
     public int volJazz { get; set; } 
     public int volPop { get; set; } 
     public void accept(Widget wc) 
     { 
      wc.visit(this); 
     } 
    } 

    public class Channel : WidgetControls 
    { 
     public int channelsProvided { get; set; } 
     public int premiumChannels { get; set; } 
     public void accept(Widget wc) 
     { 
      wc.visit(this); 
     } 
    } 

    //Widget lite implementation. Notice the accept control implementation 
    //in lite and pro. 
    //Display function is an illustration on an entry point which calls the 
    //other visit functions. This can be replaced by any suitable function(s) 
    //of your choice 
    public class WidgetLite : Widget 
    { 
     public void visit(Volume vol) 
     { 
      Console.WriteLine("Widget Lite: volume level " + vol.volLevel); 
     } 

     public void visit(Channel cha) 
     { 
      Console.WriteLine("Widget Lite: Channels provided " + cha.channelsProvided); 
     } 

     public void Display(AllControls ac) 
     { 
      foreach (var control in ac.controls) 
      { 
       control.accept(this); 
      } 

      Console.ReadKey(true); 
     } 
    } 

    //Widget pro implementation 
    public class WidgetPro : Widget 
    { 
     public void visit(Volume vol) 
     { 
      Console.WriteLine("Widget Pro: rock volume " + vol.volLevel); 
      Console.WriteLine("Widget Pro: jazz volume " + vol.volJazz); 
      Console.WriteLine("Widget Pro: jazz volume " + vol.volPop); 
     } 

     public void visit(Channel cha) 
     { 
      Console.WriteLine("Widget Pro: Channels provided " + cha.channelsProvided); 
      Console.WriteLine("Widget Pro: Premium Channels provided " + cha.premiumChannels); 
     } 

     public void Display(AllControls ac) 
     { 
      foreach (var control in ac.controls) 
      { 
       control.accept(this); 
      } 

      Console.ReadKey(true); 
     } 
    } 

    //This is a public class that holds and defines all the 
    //controls you want to define or operate on for your widgets 
    public class AllControls 
    { 
     public WidgetControls [] controls { get; set; } 

     public AllControls(int volTot, int volJazz, int volPop, int channels, int chanPrem) 
     { 
      controls = new WidgetControls [] 
      { 
       new Volume{volLevel = volTot, volJazz = volJazz, volPop = volPop}, 
       new Channel{channelsProvided = channels, premiumChannels = chanPrem} 
      }; 
     } 
    } 

    //finally, main function call 
    public class Program 
    { 
     static void Main(string[] args) 
     { 
      AllControls centralControl = new AllControls(3, 4, 2, 5, 10); 

      WidgetLite wl = new WidgetLite(); 
      WidgetPro wp = new WidgetPro(); 

      wl.Display(centralControl); 
      wp.Display(centralControl); 

     } 
    } 
} 
+0

-1你應該解釋爲什麼它會幫助他。舉例說明,而不是引用任意模式。 (如果你解決了這個問題,我會贊成的) – jgauffin

+0

@jgauffin,我會盡快更新它適合的解釋! – TheSilverBullet

+0

@jgauffin,這裏是一個粗略的解釋。我指的是我在初始答案中提供的維基鏈接。我也提到[this](http://stackoverflow.com/questions/2604169/could-someone-in-simple-terms-explain-to-me-the-visitor-patterns-purpose-with-e/2604294 #2604294)寫得非常好的解釋。請檢查這個問題的第二個答案。在這裏,'WidgetLite'和'WidgetPro'是實現'visit'功能的兩個訪客類。 「接受」這些訪問者的音量和頻道等控件。 – TheSilverBullet