在设计模式中可替代枚举

本文关键字:枚举 设计模式 | 更新日期: 2023-09-27 18:01:36

考虑一个基本组件base具有像

这样的enum类型的情况
public enum ItemState = { red, green, blue };

我在Project_1, Project_2等其他组件中使用此基础组件。

它们每个都做一些特定的事情,并且需要特定于项目的状态,例如Project_1中的{grey, black, white, ...}Project_2中的{brown, transparent, ...}

Project_1不允许使用(如果可能的话甚至不允许看到){brown, transparent, ...}。同理,Project_2不能使用{grey, black, white, ...}

我知道"局部枚举"不存在——那么对于这样的任务,建议的设计模式是什么?

在设计模式中可替代枚举

由于枚举不能继承,一种解决方案可能是使用具有静态常量成员的类,如下所示:

public class ItemState
{
    protected ItemState() { }
    public static ItemState red { get; } = new ItemState();
    public static ItemState green { get; } = new ItemState();
    public static ItemState blue { get; } = new ItemState();
}

然后在你的Project_1中你可以派生一个自己的类:

public class ItemState_1 : ItemState
{
    public static ItemState grey { get; } = new ItemState_1();
    public static ItemState black white { get; } = new ItemState_1();
}

Project_2

public class ItemState_2 : ItemState
{
    public static ItemState brown { get; } = new ItemState_2();
    public static ItemState transparent white { get; } = new ItemState_2();
}

这可能不是最舒服的方式,但这是我目前能想到的最好的方式。

你可以这样使用它们:

ItemState project1State = ItemState_1.grey;
if (project1State == ItemState_1.grey)
   // do something

这些都编译得很好,但不幸的是,这些值不能在switch/case语句中使用。这可以通过适当的ToString()实现来解决,字符串字面值可以在switch/case中使用。但是,这当然会给这些类/属性定义添加更多的代码。

我有点晚了,但这里是Rene的回答的"buff"版本(现在使用隐式强制转换!):

public class ColorEnum
{
    protected readonly string Name;
    protected readonly Color Value;
    public static readonly ColorEnum Red = new ColorEnum(Color.Red, "Red");
    public static readonly ColorEnum Green = new ColorEnum(Color.Green, "Green");
    public static readonly ColorEnum Blue = new ColorEnum(Color.Blue, "Blue");
    protected ColorEnum(Color value, string name)
    {
        Name = name;
        Value = value;
    }
    public override string ToString()
    {
        return Name;
    }
    public static implicit operator Color(ColorEnum @enum)
    {
        return @enum.Value;
    }
    public static implicit operator string(ColorEnum @enum)
    {
        return @enum.Name;
    }
}
public class AnotherColorEnum : ColorEnum
{
    public static readonly ColorEnum Grey = new AnotherColorEnum(Color.Gray, "Grey");
    public static readonly ColorEnum Black = new AnotherColorEnum(Color.Black, "Black");
    public static readonly ColorEnum White = new AnotherColorEnum(Color.White, "White");
    protected AnotherColorEnum(Color value, string name) : base(value, name)
    {
    }
}

这样你就可以像这样使用你的"enum":

    var color = ColorEnum.Red;
    var anothercolor = Color.Red;
    if (color == anothercolor)
    {
            //DoSomething
    }

或者像这样:

    var color = ColorEnum.Red;
    var anothercolor = "Red";
    if (color == anothercolor)
    {
            //DoSomething
    }

根据您的用例,您可能希望使用主/子集模式。

例如,我有一个包含所有可能值的enum:

/// <summary>
/// Types of limits that can be applied to a table, view, or table-value function query.
/// </summary>
/// <remarks>Databases are expected to provide their own enumeration that represents a subset of these options.</remarks>
[Flags]
public enum LimitOptions
{
    /// <summary>
    /// No limits were applied.
    /// </summary>
    None = 0,
    /// <summary>
    /// Returns the indicated number of rows with optional offset
    /// </summary>
    Rows = 1,
    /// <summary>
    /// Returns the indicated percentage of rows. May be applied to TableSample
    /// </summary>
    Percentage = 2,

    /// <summary>
    /// Adds WithTies behavior to Rows or Percentage
    /// </summary>
    WithTies = 4,

    /// <summary>
    /// Returns the top N rows. When there is a tie for the Nth record, this will cause it to be returned. 
    /// </summary>
    RowsWithTies = Rows | WithTies,
    /// <summary>
    /// Returns the top N rpercentage of ows. When there is a tie for the Nth record, this will cause it to be returned. 
    /// </summary>
    PercentageWithTies = Percentage | WithTies,

然后每个项目有它自己的值子集:

/// <summary>
/// Limit options supported by Access.
/// </summary>
/// <remarks>This is a strict subset of LimitOptions</remarks>
public enum AccessLimitOption
{
    /// <summary>
    /// No limits were applied.
    /// </summary>
    None = LimitOptions.None,
    /// <summary>
    /// Uses TOP
    /// </summary>
    RowsWithTies = LimitOptions.RowsWithTies,
}

子项目总是使用严格的子集,而不是使枚举可扩展。这允许我保持核心相当通用,同时在适当的地方提供特定于数据库的api。