2012-03-05 3 views
4

私はInterfaceがISendOutと言っています。これは2つの異なるクラスを継承しています たとえばTransferViaSerialPortとTransferViaWirelessModule(これらの2つのクラスでこのInterfaceを実装することを意味します)。 SerialPortまたはWirelessModuleでデータを送信する方法と、OCPに違反しない方法の間で、ユーザーが(UI内)を選択できるようにするにはどうすればよいですか? 「Switch Case」または「If/Else」のステートメントを使用したい場合、私はOCPに違反します。インターフェイスから継承された異なるクラスの中から選択したいときにOCPに違反しない方法は?

+0

(そうOCPを速報ではない)既存のコードを変更せずにUsbSendOutを追加します。 – thedev

答えて

2

ファクトリパターンを使用する必要があります。ファクトリパターンをダイナミックにするには、にリフレクションを使用し、のクラスのタイプを表示するには、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."); 
    } 
} 
1

をチェックコンストラクタに渡し、C#のdynamic dispatchに "switch case"を実行させます。

これは、インターフェイスが非常に便利な理由です。間接指定があり、OCPを満たすためにdependency injectionを実行できます。

+0

あなたの答えをありがとう。 「UI」でデータを送信する方法を選択させたいと思っています。例えば、あなたはデータを送信する2つの方法があります。もう1つはシリアルです。データを送信するより多くのタイプがあると想像してください。どのように私はユーザーにUIでこれらのメソッドを選択する能力を与えることができますか? –

1

クラス自体は、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が必要です。

+0

あなたはそれが間違っていることを知っていますか?私はUIにデータを送信する方法をユーザーが選択できるようにしたいと考えています。送信方法として、赤外線経由で発信する方法や、異なる方法の中から選択させることによって、UI上にOCPに違反する 'if'文を持たせる必要があります。なぜなら新しいタイプのSending Outは私に新しい 'if/else'条件を強制するからです。 –

+0

ワン・エリアでのみ。それが私が工場に言及した理由です。 – jgauffin

+0

@MehrdadKamelzadeh:私の更新を読んでください。 – jgauffin

関連する問題