4

我正在建立一个本地化目录并且有一个设计困境。现在,目录存储 aDictionary<string, IString>来存储翻译,其中IString可以有两种类型:SingularPlural. 这是一个简化版本IString

public interface IString
{
    void SetSingular(string singular);

    string GetSingular(params object[] args);

    void SetPlural(PluralCategory category, string plural);

    string GetPlural(PluralCategory category, params object[] args);
}

然后,当我实现 时Singular,我为复数方法抛出一个NotSupportedException,它被目录捕获,并且Plural对单数方法执行相同的操作。

public class Singular : IString
{
    // ...

    public string GetPlural(PluralCategory category, params object[] args)
    {
        throw new NotSupportedException(string.Format(
            "Singular strings don't support GetPlural({0}, {1})",
            category, args));
    }

    public void SetPlural(PluralCategory category, string plural)
    {
        throw new NotSupportedException(string.Format(
            "Singular strings don't support SetPlural({0}, {1})",
            category, plural));
    }
}

这种设计源于要求keys对于单数和复数都必须是唯一的,但是我觉得实现不相关的方法和throwNotSupportedException不好闻。

第二种设计是存储一个Dictionary<string, StringType>用于密钥检查的,其中StringType是一个枚举,然后有两个额外的字典Dictionary<string, Singular>Dictionary<string, Plural>根据StringType. 这使它稍微复杂一点,但不会破坏接口概念。

所以你怎么看?我的第一个想法是不好用NotSupportedException吗?我应该选择第二种设计还是其他?

编辑:基于@dasblinkenlight 想法的更清晰的解决方案是统一接口方法以获取一个SingularPlural一个单一的。单数只有一个PluralCategory.None,而复数不允许包含这个类别。这受setter方法的限制,在具体实现定义的接口之外(setter方法不在下面展示)。

public interface IString
{
    string GetString(PluralCategory category, params object[] args);
    bool HasCategory(PluralCategory category);
}

public class Singular : IString
{
    private string Text;

    public string GetString(PluralCategory category, params object[] args)
    {
        if (category == PluralCategory.None)
        {
            if (Text == null || args == null || args.Length == 0)
            {
                return Text;
            }
            return string.Format(Text, args);
        }
        return null;
    }

    public bool HasCategory(PluralCategory category)
    {
        return category == PluralCategory.None;
    }
}

public class Plural : IString
{
    private Dictionary<PluralCategory, string> Texts = new Dictionary<PluralCategory, string>();

    public string GetString(PluralCategory category, params object[] args)
    {
        string text;
        if (Texts.TryGetValue(category, out text))
        {
            if (text == null || args == null || args.Length == 0)
            {
                return text;
            }
            return string.Format(text, args);
        }
        return null;
    }

    public bool HasCategory(PluralCategory category)
    {
        return Texts.ContainsKey(category);
    }
}
4

1 回答 1

7

你是对的,在这样的情况下投入不是一个好主意NotSupportedException。通常,您实现一个接口是为了提供一组通用操作,这些操作“统一”一组不同的类,为一组通用操作提供不同的实现。

但是,在您的情况下,不同的类无法“统一”:它们不仅保留了自己的实现,还保留了自己的接口。当您尝试统一使用它们时,代码会引发异常。与保留它们相比,通用接口并没有为您提供那么多- 用户在进行调用之前object必须知道.IStringNotSupportedException

有几种方法可以解决这个问题:一种方法是统一单数和复数方法,返回比简单的更复杂的答案string

public enum SingularOrPluralCategory {
    Singular,
    // The rest of the PluralCategory enum values
}
public class StringForm {
    public string Text {get; private set;}
    public SingularOrPluralCategory Category {get; private set;}
}
public interface IString {
    // You may want to omit the setter from the interface, adding it to the class instead
    void SetForm(SingularOrPluralCategory category, string plural);
    StringForm GetForm(SingularOrPluralCategory category, params object[] args);
}

现在单数实现将返回StringForm中的SingularCategory,而复数实现将返回StringForm几个复数类别之一。尝试在 的单数子类上设置复数类别IString可能仍然是错误的,但您可以通过将设置器移动到类上来解决此问题,从而无法调用具有 的单数子类上的类别的设置器IString

于 2013-08-05T01:10:24.527 回答