私はInterfaceがISendOut
と言っています。これは2つの異なるクラスを継承しています たとえばTransferViaSerialPortとTransferViaWirelessModule(これらの2つのクラスでこのInterfaceを実装することを意味します)。 SerialPort
またはWirelessModule
でデータを送信する方法と、OCPに違反しない方法の間で、ユーザーが(UI内)を選択できるようにするにはどうすればよいですか? 「Switch Case」または「If/Else」のステートメントを使用したい場合、私はOCPに違反します。インターフェイスから継承された異なるクラスの中から選択したいときにOCPに違反しない方法は?
答えて
ファクトリパターンを使用する必要があります。ファクトリパターンをダイナミックにするには、にリフレクションを使用し、のクラスのタイプを表示するには、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);
}
}
後、私はクラスがそれをimplemetsインタフェースを継承しません
[DisplayName("Usb")]
public class UsbSendOut : ISendOut
{
public void Send(string data)
{
MessageBox.Show("data sent through usb.");
}
}
あなたは、例えば、パラメータとしてISendOut
の実装を渡す戦略パターン https://en.wikipedia.org/wiki/Strategy_pattern
http://www.dofactory.com/Patterns/PatternStrategy.aspx#_self1
をチェックコンストラクタに渡し、C#のdynamic dispatchに "switch case"を実行させます。
これは、インターフェイスが非常に便利な理由です。間接指定があり、OCPを満たすためにdependency injectionを実行できます。
あなたの答えをありがとう。 「UI」でデータを送信する方法を選択させたいと思っています。例えば、あなたはデータを送信する2つの方法があります。もう1つはシリアルです。データを送信するより多くのタイプがあると想像してください。どのように私はユーザーにUIでこれらのメソッドを選択する能力を与えることができますか? –
クラス自体は、OCPに違反するが、その実装を使用して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を破壊を防止することができますが、それは簡単に工場を用いて固定することができます作成します。 )。
更新
あなたはそれと間違って何を知っていますか?私はUIにデータを送信する方法をユーザーが選択できるようにしたいと考えています。送信方法として、赤外線経由で送信する方法や、さまざまな方法の中からユーザーに選択させることによって、OCPに違反するユーザーのUIにifステートメントを持たせる必要があります。発送のすべての新しい種類が新しいのif/else条件に
を持つために私を強制しますので私のアプローチは、代わりにISendOut
インタフェースが使用されているすべての単一の場所で、一つだけのクラスにOCPの違反を移動します。
私も工場について言及しました。私は工場のパターン(抽象的な工場または工場のどちらの方法も意味しません)を意味します。コンフィグレーション文字列と具象クラスをマップし、UserConfiguredCommunicationModule
内のそのファクトリを使用して、適切なISendOut
実装を作成することができます。
UserConfiguredCommunicationModule
内のサービスロケータパターンを使用して、正しい実装を解決することもできます。
その点はあなたが選択したものであるにもかかわらず、選択プロセスをカプセル化するのに似たクラスUserConfiguredCommunicationModule
が必要です。
- 1. クラスから継承したクラスとDelphiのインターフェイスから継承するクラスを作成できますか?
- 2. CSS - IEで異なる親から継承したGrandchildクラス
- 3. のJava:私が使用したときに異なるパッケージの別のクラスにアクセスしない保護された方法は、多重継承
- 4. コントローラまたはヘルパーから継承されないクラスのMVC3での設定
- 5. 他のクラスから継承したクラスは継承を使用しないクラスよりもメモリ内で大きくなっていますか?
- 6. 生成されたクライアントクラスがServiceContractインターフェイスから継承しないのはどうですか?
- 7. 仮想デストラクタを持たないクラスから継承する
- 8. Javaクラスが実装されたインタフェースからアノテーションを継承しないのはなぜですか?
- 9. UML - クラス継承、あなたは何を継承しますか?
- 10. オブジェクトがインターフェイスから継承する抽象クラスを継承する場合、オブジェクトはインターフェイスから継承されますか?
- 11. 別のクラスから継承したクラスを模擬してください
- 12. 継承されたクラスの違いをどのように扱いますか?
- 13. インターフェイスまたはImplimentインターフェイスからの継承?
- 14. 継承されたフィールドを新しいコンテンツタイプから削除する方法
- 15. インターフェイスはあいまいに継承されたフィールド
- 16. DbContextクラスから継承する方法
- 17. クラス 'オブジェクト'から作成したクラスを継承するのはなぜよいのでしょうか?
- 18. 異なるパンダのデータフレームから選択した列を掛ける方法
- 19. Rational(またはコンストラクタを持たない任意のクラス)からどのように継承できますか?
- 20. 親密なネストされたクラス継承
- 21. 直接親ではない基底クラスからコンストラクタを継承する方法
- 22. 異なるパッケージのクラスによるパッケージ保護されたメソッドの継承
- 23. インターフェイスから派生した別のクラスの中にあるインターフェイスから派生したクラスをインスタンシエートする...ちょっと調べるためには
- 24. MediaStoreから返されない選択された画像
- 25. 実装クラスは実装されたインターフェイスからXMLコメントを「継承できますか?
- 26. ListActivityが継承したときにonClickListenerが機能しない
- 27. C++継承されたテンプレートクラスは基本クラスにアクセスできない
- 28. 継承したクラスのメソッドが基底クラスに渡された
- 29. ベースがEF4.1 DbContextから来たときに継承されたクラスを作成するには?
- 30. 継承されていないインターフェイスのみを検索しますか?
(そうOCPを速報ではない)既存のコードを変更せずにUsbSendOutを追加します。 – thedev