如何在不使用枚举的情况下对两个多态类之间的关联进行建模?

本文关键字:多态 两个 之间 关联 建模 枚举 情况下 | 更新日期: 2023-09-27 18:11:57

我使用enum标记两种不同类别的产品- SensorDevice和[data]CaptureDevice。它们的目的是在物理上相互连接,但并不是每个传感器模型都可以被每个接收器模型使用,所以我为不同的平台创建了一个Enum,这样GUI将只显示给定设备的兼容配件:

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!
    }
}

我开始发现这很臭,因为枚举是硬编码的。我正在考虑使用"用多态替换类型代码"重构,但我不太确定如何针对这种情况做到这一点。任何建议吗?

如何在不使用枚举的情况下对两个多态类之间的关联进行建模?

您可以执行以下操作来删除enum。

用类替换enum

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

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

你可以这样配置你的平台:

<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; }
}