I have an Interface lets say ISendOut
which I've inherited two different classes from it
for example TransferViaSerialPort and TransferViaWirelessModule (I mean implement this Interface in these two classes). How can I design my software to both giving the ability to the user to choose (IN THE UI) between the methods of sending his/her data out via SerialPort
or WirelessModule
and not violate the OCP? Because if I want to have a "Switch Case" or an "If/Else" statement I will Violate the OCP.

- 1,764
- 2
- 21
- 39
-
A class does not inherit an interface it implemets it. – thedev Mar 06 '12 at 14:15
4 Answers
You need to use the Factory Pattern. And to make the Factory Pattern dynamic you can use Reflection and to show the Types of your Classes in the UI
which are Implemented from ISendOut
you can use Custom Attributes or other methods like using a 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);
}
}
Later I add UsbSendOut without modifying existing code (so not Breaking the OCP)
[DisplayName("Usb")]
public class UsbSendOut : ISendOut
{
public void Send(string data)
{
MessageBox.Show("data sent through usb.");
}
}

- 36
- 3
You pass your implementation of ISendOut
as a parameter, e.g. to a constructor, and let C#'s dynamic dispatch do the "switch case", as you've put it.
That's why interfaces are so useful: you have an indirection and can do dependency injection to meet OCP.

- 7,078
- 4
- 50
- 90
-
Thanks for your answer. I want to let the user to select the way of sending out the data in `UI`. for example you have two way of sending out the data one is Wireless the other is Serial and imagine we will have much more types of sending out the data. how can I give the ability of selecting these methods in UI to the user? – Mehrdad Kamelzadeh Mar 06 '12 at 14:56
Create a UserConfiguredCommunicationModule
class (favor composition over inheritance)
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);
}
}
Using that implementation will prevent you from breaking OCP (although the class itself violates OCP, but that can easily be fixed by using a factory in it).
Update
you know what's wrong with that? I want to give the ability to the user to choose the method of Sending Out the Data in the UI. Now imagine that we will have much more methods of Sending Out i.e. Sending Out Via Infrared or ... so by letting the user choose between different methods, I have to have an if statement in my UI which it will violate the OCP. Because every new type of Sending Out will force me to have new if/else condition
My approach move the violation of OCP into one class only, instead of every single place where the ISendOut
interface is used.
I also mentioned factory, in which I mean the factory pattern (neither abstract factory or factory method). You can use it to map between configuration strings and the concrete classes and use that factory inside of UserConfiguredCommunicationModule
to create the proper ISendOut
implementation.
You can also use service locator pattern within the UserConfiguredCommunicationModule
to resolve the correct implementation.
That point is no matter what you choose, you need a UserConfiguredCommunicationModule
similar class to encapsulate the selection process.

- 99,844
- 45
- 235
- 372
-
you know what's wrong with that? I want to give the ability to the user to choose the method of Sending Out the Data in the UI. Now imagine that we will have much more methods of Sending Out i.e. Sending Out Via Infrared or ... so by letting the user choose between different methods, I have to have an `if` statement in my UI which it will violate the OCP. Because every new type of Sending Out will force me to have new `if/else` condition. – Mehrdad Kamelzadeh Mar 06 '12 at 15:25
-
Check out the strategy pattern https://en.wikipedia.org/wiki/Strategy_pattern
http://www.dofactory.com/Patterns/PatternStrategy.aspx#_self1

- 2,816
- 8
- 34
- 47