如何在不使用枚举的情况下模拟两个多态类之间的关联

时间:2016-10-06 14:23:33

标签: c# oop enums polymorphism model-associations

我使用enum来标记两种不同类别的产品 - SensorDevice和[data] CaptureDevice。 它们旨在用于物理上相互插入,但并非每个接收器模型都可以使用每个传感器模型,因此我为不同的平台创建了一个Enum,因此GUI只显示给定设备的兼容附件: / p>

enum Platform {
    Standard,
    Deluxe,
    Jumbo
}

abstract class CaptureDevice
{
    public Platform platform;

    public bool IsCompatibleWith(SensorDevice sd)
    {
        return sd.Platforms.Contains(this.Platform); // <- this is type-checking!
    }
}

abstract class SensorDevice
{
    public IEnumerable<Platform> Platforms;

    public bool IsCompatibleWith(CaptureDevice cd)
    {
        return this.Platforms.Contains(cd.Platform); // <- this is type-checking!
    }
}

我开始觉得这很臭,因为枚举是硬编码的。我正在考虑使用“通过多态性替换类型代码”重构,但我不太确定如何为这种情况做这件事。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

你可以做以下事情来摆脱枚举。

用类替换枚举。

public abstract class Platform {}

添加Device类,如果它与Platform兼容,则会回答。

public abstract class Device
{
    public abstract bool IsCompatibleWith(Platform platform);
}

使CaptureDevice成为Device的子类。

public abstract class CaptureDevice : Device
{
    public Platform Platform;

    public override bool IsCompatibleWith(Platform platform)
    {
        // I'm using type comparison for the sake of simplicity,
        // but you can implement different business rules in here.

        return this.Platform.GetType() == platform.GetType();
    }

    public bool IsCompatibleWith(SensorDevice sd)
    {
       // We are compatible if sensor is compatible with my platform.

        return sd.IsCompatibleWith(this.Platform);
    }
}

使SensorDevice成为Device的子类。

public abstract class SensorDevice : Device
{
    public IEnumerable<Platform> Platforms;

    public override bool IsCompatibleWith(Platform platform)
    {
        // I'm using type comparison again.

        return this.Platforms.Any(p => p.GetType() == platform.GetType());
    }

    public bool IsCompatibleWith(CaptureDevice cd)
    {
        // We are compatible if capture is compatible with one of my platforms. 

        return this.Platforms.Any(p => cd.IsCompatibleWith(p));
    }
}

基本上,这就是你需要做的。为了说明它是如何工作的,我在下面添加了代码。

// Platforms
public class StandardPlatform : Platform { }
public class DeluxPlatform : Platform { }
public class JumboPlatform : Platform { } 

// Capture device(s)
public class CD1 : CaptureDevice
{
    public CD1()
    {
        Platform = new StandardPlatform();
    }
}

// Sensor device(s)
public class SD1 : SensorDevice
{
    public SD1()
    {
        Platforms = new List<Platform>
        {
            new StandardPlatform(),
            new DeluxPlatform()
        };
    }
}

public class SD2 : SensorDevice
{
    public SD2()
    {
        Platforms = new List<Platform> {new JumboPlatform()};
    }
}

// Somewhere in the code...
var cd1 = new CD1();
var sd1 = new SD1();

Console.WriteLine(cd1.IsCompatibleWith(sd1)); // True
Console.WriteLine(sd1.IsCompatibleWith(cd1)); // True

var sd2 = new SD2();
Console.WriteLine(sd2.IsCompatibleWith(cd1)); // False
Console.WriteLine(cd1.IsCompatibleWith(sd2)); // False

答案 1 :(得分:0)

编辑:如果你想摆脱枚举,为什么不能使用配置文件?

您可以像这样配置您的平台:

<Platforms>
    <Platform name="Standard">
        <Device>Namespace.of.your.Device.CaptureDevice</Device>
        <Device>Namespace.of.another.Device.AnotherDevice</Device>
    </Platform>
    <Platform name="Deluxe">
        <Device>Namespace.of.your.Device.CaptureDevice</Device>
    </Platform>
</Platforms>

其他语法:

<Platforms>
    <Platform>
        <Name>Standard</Name>
        <Devices>
            <Device>Namespace.of.your.Device.CaptureDevice</Device>
            <Device>Namespace.of.another.Device.AnotherDevice</Device>
        <Devices>
    </Platform>
</Platforms>

然后,你有相同的基础结构,你可以做这样的事情:

abstract class ADevice<T> where T : ADevice<T>
{
    public ADevice<T>(T device , string filename)
    {
        // Parsing of the file
        // Plus, setting the Platforms Property
    }

    // Or (but you should keep the first constructor to see the filename dependency)
    public ADevice<T>(T device)
    {
        // Parsing of the file
    }

    public IEnumerable<Platform> Platforms { get; private set; }

    public bool IsCompatibleWith(T device)
    {
        return this.Platforms.Contains(device.Platform); // <- this is type-checking!
    }
}

然后:

abstract class CaptureDevice : ADevice<CaptureDevice>
{
    public CaptureDevice(CaptureDevice device, string filename)
        : base(device, filename)
    {
    }

    // Or (But still same comment)
    public CaptureDevice(CaptureDevice device)
        : base(device, defaultFilename)
    {
    }
}

SensorDevice

相同

而不是Enum,您可以创建一个简单的类:

public class Platform
{
    public Platform(string name)
    {
        Name = name;
    }

    public string Name { get; }
}