2012-03-05 51 views
4

我有一個接口可以說ISendOut,我從它繼承了兩個不同的類 例如TransferViaSerialPort和TransferViaWirelessModule(我的意思是在這兩個類中實現此接口)。我如何設計我的軟件,讓用戶在通過SerialPortWirelessModule發送他/她的數據的方法之間選擇(在用戶界面)而不違反OCP?因爲如果我想要一個「切換案例」或「如果/否則」的聲明,我會違反OCP。當您想要在從接口繼承的不同類之間進行選擇時,如何不違反OCP?

+0

一類不繼承它implemets它的接口。 – thedev 2012-03-06 14:15:33

回答

2

您需要使用工廠模式。爲了使工廠模式動態化,您可以使用反射並在UI中顯示中實現的類的類型,您可以使用自定義屬性或其他方法,如使用Dictionary

[System.AttributeUsage(System.AttributeTargets.Class)] 
public class DisplayNameAttribute : Attribute 
{ 
    public DisplayNameAttribute(string displayName) 
    { 
     DisplayName = displayName; 
    } 

    public string DisplayName { get; set; } 
} 

public interface ISendOut 
{ 
    void Send(string data); 
} 

[DisplayName("Wireless")] 
public class WirelessSendOut : ISendOut 
{ 
    public void Send(string data) 
    { 
     MessageBox.Show("data sent through wireless."); 
    } 
} 

[DisplayName("Serial")] 
public class SerialSendOut : ISendOut 
{ 
    public void Send(string data) 
    { 
     MessageBox.Show("data sent through serial port."); 
    } 
} 

public static class SendOutFactory 
{ 
    public static ISendOut CreateSendOut(string typeName) 
    { 
     var types = Assembly.GetExecutingAssembly().GetTypes(); 
     var sendOutType = types.First(x => (typeof(ISendOut)).IsAssignableFrom(x) && x.Name == typeName); 
     return (ISendOut) Activator.CreateInstance(sendOutType); 
    } 
} 

public static class SendOutDiscovery 
{ 
    public static IEnumerable<NameType> Discover() 
    { 
     var types = Assembly.GetExecutingAssembly().GetTypes(); 
     var sendOutTypes = types.Where(x => x != typeof(ISendOut) && (typeof(ISendOut)).IsAssignableFrom(x)); 
     return sendOutTypes.Select(type => GetNameType(type)).ToList(); 
    } 

    private static NameType GetNameType(Type type) 
    { 
     var nameType = new NameType 
          { 
           DisplayName = GetDisplayName(type), 
           TypeName = type.Name 
          }; 
     return nameType; 
    } 

    private static string GetDisplayName(Type type) 
    { 
     return ((DisplayNameAttribute)type.GetCustomAttributes(typeof (DisplayNameAttribute), false).First()).DisplayName; 
    } 
} 

public class NameType //for binding in UI 
{ 
    public string DisplayName { get; set; } 
    public string TypeName { get; set; } 
} 

public class SendOutViewModel //sample using in wpf (window contains a combobox) 
{ 
    public SendOutViewModel() 
    { 
     SendTypes = new ObservableCollection<NameType>(SendOutDiscovery.Discover()); 
    } 

    public NameType SelectedSendType { get; set; } //bind to selected item in combobox 

    public ObservableCollection<NameType> SendTypes { get; private set; } //bind to item source of combo 

    public string Data { get; set; } //data to be sent 

    public void Send() 
    { 
     ISendOut sendOut = SendOutFactory.CreateSendOut(SelectedSendType.TypeName); 
     sendOut.Send(Data); 
    } 
} 

後來我添加UsbSendOut無需修改現有的代碼(因此不是打破OCP)

[DisplayName("Usb")] 
public class UsbSendOut : ISendOut 
{ 
    public void Send(string data) 
    { 
     MessageBox.Show("data sent through usb."); 
    } 
} 
1

你通過的ISendOut實現作爲參數,例如到一個構造函數,並讓C#的dynamic dispatch執行「switch case」,就像你說的那樣。

這就是爲什麼界面非常有用:你有一個間接的,並可以做dependency injection以滿足OCP。

+0

感謝您的回答。我想讓用戶選擇在UI中發送數據的方式。比如你有兩種發送數據的方式,一種是Wireless,另一種是Serial,想象一下,我們將有更多類型的發送數據。我如何能夠在用戶界面中選擇這些方法? – 2012-03-06 14:56:09

1

創建UserConfiguredCommunicationModule類(在繼承青睞組成)

public class UserConfiguredCommunicationModule : ISendOut 
{ 
    public UserConfiguredUserModule(SerialPort serial, WirelessModule wireless) 
    {} 

    public void Send(string data) 
    { 
     if (UserIdentity.Current.PrefersSerial) 
      serial.Send(data); 
     else 
      wireless.Send(data); 
    } 
} 

使用實施將防止你破壞OCP(雖然類本身違反了OCP,但可以很容易地通過它使用工廠固定)。

更新

你知道什麼是錯?我想讓用戶能夠選擇在UI中發送數據的方法。現在想象一下,我們將有更多的發送方法,即通過紅外線發送或...通過讓用戶選擇不同的方法,我必須在我的用戶界面中有一個if語句,這將違反OCP。因爲每一個新的類型發出將迫使我有新的if/else條件

我的做法違反OCP的進入只有一個類,而不是在使用的ISendOut接口的每一個地方。

我還提到了工廠,我的意思是工廠模式(既不是抽象工廠也不是工廠方法)。您可以使用它來映射配置字符串和具體類,並使用UserConfiguredCommunicationModule中的該工廠創建適當的ISendOut實現。

您還可以使用UserConfiguredCommunicationModule內的服務定位器模式來解決正確的實現。

這一點不管你選擇什麼,你需要一個UserConfiguredCommunicationModule類似的類來封裝選擇過程。

+0

你知道這有什麼問題嗎?我想讓用戶能夠選擇在UI中發送數據的方法。現在想象一下,我們將有更多的發送方法,即通過紅外線發送或...通過讓用戶在不同的方法之間進行選擇,我必須在我的用戶界面中有一個「if」語句,這將違反OCP。因爲每種新型的發送都會迫使我有新的'if/else'條件。 – 2012-03-06 15:25:27

+0

僅限一處。這就是爲什麼我提到工廠 – jgauffin 2012-03-06 16:09:54

+0

@MehrdadKamelzadeh:閱讀我的更新。 – jgauffin 2012-03-06 19:19:23