我有一個接口可以說ISendOut
,我從它繼承了兩個不同的類 例如TransferViaSerialPort和TransferViaWirelessModule(我的意思是在這兩個類中實現此接口)。我如何設計我的軟件,讓用戶在通過SerialPort
或WirelessModule
發送他/她的數據的方法之間選擇(在用戶界面)而不違反OCP?因爲如果我想要一個「切換案例」或「如果/否則」的聲明,我會違反OCP。當您想要在從接口繼承的不同類之間進行選擇時,如何不違反OCP?
回答
您需要使用工廠模式。爲了使工廠模式動態化,您可以使用反射並在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.");
}
}
你通過的ISendOut
實現作爲參數,例如到一個構造函數,並讓C#的dynamic dispatch執行「switch case」,就像你說的那樣。
這就是爲什麼界面非常有用:你有一個間接的,並可以做dependency injection以滿足OCP。
感謝您的回答。我想讓用戶選擇在UI中發送數據的方式。比如你有兩種發送數據的方式,一種是Wireless,另一種是Serial,想象一下,我們將有更多類型的發送數據。我如何能夠在用戶界面中選擇這些方法? – 2012-03-06 14:56:09
創建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
類似的類來封裝選擇過程。
- 1. 當您需要從模板中繼承時,您如何從模板類繼承?
- 2. 在同一類的不同實現之間進行選擇
- 3. 如何在一天中的兩個不同時間之間進行選擇
- 4. 如何在不同的CDI bean實現之間進行選擇運行時
- 5. 在抽象類和接口之間進行選擇
- 6. 如何共享從不同類繼承的兩個類之間的數組
- 7. 在不同的ORM之間進行選擇時,主要標準是什麼
- 8. 選擇當前類的方法,而不是繼承的類
- 9. Python - 選擇要繼承的類
- 10. 在JSON模式中的不同對象之間進行選擇
- 11. 要繼承還是不繼承?一些專業意見想要
- 12. 從接口繼承
- 13. 接口要求繼承基類
- 14. 模板選擇在不違反DRY prinicple
- 15. 如何在VS.NET中的窗口之間進行選擇?
- 16. 爲什麼不能從接口繼承
- 17. 如何從B繼承B類同時繼承B?
- 18. 在兩種不同形式之間進行選擇
- 19. 從時間戳時區之間進行選擇(日期時間)
- 20. 接口繼承和接口之間的區別
- 21. 如何在C++中的不同類之間進行轉換?
- 22. 包之間的繼承不存在?
- 23. 在時間範圍之外選擇不同的行
- 24. 如何知道類是從類還是接口繼承的?
- 25. 如何在模型和ActiveRecord :: Base之間進行繼承?
- 26. 如何在繼承的java類,當子和超類在不同的包
- 27. 接口,子類,繼承
- 28. oop接口,繼承,基類,
- 29. GWT類繼承接口
- 30. 如何繼承接口
一類不繼承它implemets它的接口。 – thedev 2012-03-06 14:15:33