简体   繁体   中英

Is there a design pattern that can help me store object "capabilities"?

I am working on a C# program that allows a user to interact with and configure various AV devices such as receivers and switchers over a TCP telnet style connection (according to the command sets of the various device manufacturers). I use the command pattern to encapsulate the commands. The app can only interact with one device at a time, so when it connects it enumerates the device and creates a DeviceVersion object. This object stores certain properties that are common to all the devices. It also needs to maintain a list of capabilities for each device. For instance some devices do not have volume control. Others do, but don't have the ability to change input devices. I hate the idea of storing a long list of booleans inside each DeviceVersion object. I think I should have something like a CapabilityContract object that encapsulates a dictionary such as Dictionary which can map capability names to booleans. At least that way I can put in a ContractFactory or something that can generate those capability objects on the fly, either through text config files or some other method.

However, when it comes to parsing command output, in some cases the capabilities allowed may change how a response is parsed. For instance an AV switch that can separate audio and video on an output may have a GetInput command which returns an ordered pair like (audio input, video input), however, on a device where audio and video are always linked it may just return (input). The command parser interface implementation maintains a reference back to the DeviceVersion, so it can look up the capabilities but that leads to quite a few if statements, or switch statements. I toyed with the idea of generating a different parser implementation for each DeviceVersion type, but that will lead to a lot of duplicated code. Is there some design pattern I am missing that can simplify this problem for me and avoid a lot of either maintaining boolean values, or lots of duplicate code?

It's not clear what is the aim of DeviceVersion class, maybe DeviceInfo describes it better. My suggestion is to use IDeviceCapability collection where each item represent one capability such as IPlayable. This way you can attach/detach, get info, enable/disable and do other things with all capabilities but with only one implementation for all specific capabilities. Though you can override them anyway.

Another good thing about this is that you can test and mock each capability separately of DeviceInfo class. Changes in DeviceCapability doesn't affect DeviceInfo and all DeviceCapability implementations.

If I was to approach this problem I would go with a Factory Pattern , also on MSDN , where I defined a Base Interface (no implementation) or Abstract class (contains some implementation) and then a Factory to retrieve these objects.

This way you have a common implementation for your system to communicate with these Devices and you aren't duplicating code because you are just inheriting the base class to create implementations for each device you may interface with. I'd suggest that you make your DeviceVersion object a little more generic and turn that into the base class. You can wrap up your command pattern implementation into the Factory Pattern and that should help you get there.

I used this pattern a while back to implement a C# application that would allow you to switch between four different types of DVRs using four different SDKs.

This is a quick and dirty example:

DeviceType Enum:

public enum DeviceType {
  Receiver,
  Switcher
  // etc
}

Base Class:

public interface DeviceVersion {
  // What type is this?
  DeviceType DeviceType { get; }

  // Common Properties and Methods, etc here
  #region Function Availability Properties

  bool CanFastForward { get; }
  bool CanPlay { get; }
  bool CanStop { get; }
  bool Can... { get; }
  ...

  #endregion

  #region Methods

  bool Connect(string ipAddress, string user, string password);
  void Disconnect();
  void Play();
  void Stop();
  ...

  #endregion
}

Switcher Class:

public class Switcher : DeviceVersion {
  // Override the virtual
  public DeviceType DeviceType { get { return DeviceType.Switcher; } }

  public bool CanPlay
  {
      get { return true; }
  }
  ...
}

Factory Class:

public class DeviceFactory {
  // This is the factory method
  public static DeviceVersion GetDevice(DeviceType type) {
    switch (type) {
      case DeviceType.Switcher:
        return new Switcher();
      case DeviceType.Receiver:
        ...
      default:
        ...
    }
  }
}

Then in your main methods when you are connecting to a different device you'd go:

...
var currentDeviceType = DeviceTypes.Switcher;
...
var device = DeviceFactory.GetDevice(currentDeviceType);
if (device.Connect("1.2.3.4", "user", "pass")) {
  if (device.CanPlay)
    device.Play();
  ...
}
...

As for the contracts and capabilities you could implement a dictionary or similar in the base class to hold those items as everything in the base class is inherited by the classes that inherit from it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM