我正在构建本地化目录并且存在设计困境。目前,目录存储Dictionary<string, IString>
来存储翻译,其中IString
可以有两种类型:Singular
或Plural
。这是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));
}
}
这种设计来自于对单数和复数键必须唯一的要求,但我觉得实现非相关方法并抛出NotSupportedException
并不能很好地发挥作用。
第二种设计是存储Dictionary<string, StringType>
进行密钥检查,其中StringType
是枚举,然后使用两个额外的词典Dictionary<string, Singular>
和Dictionary<string, Plural>
来使用取决于StringType
的值。这使它更复杂,但不会破坏界面概念。
那么,您怎么看?我的第一个想法是NotSupportedException
使用不当吗?我应该选择第二种设计还是其他设计?
编辑:基于@dasblinkenlight理念,更清晰的解决方案是统一界面方法,将Singular
或Plural
合并为一个。{1}}或PluralCategory.None
。单数只有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);
}
}
,而Plurals永远不允许包含此类别。这受限于setter方法,由特定实现定义的接口之外(setter方法不在下面显示)。
{{1}}
答案 0 :(得分:7)
你是对的,把NotSupportedException
扔在这种情况下不是一个好主意。通常,您实现的接口是提供一组通用的操作,以便统一&#34;一组不同的类,为一组常见操作提供不同的实现。
但是,在您的情况下,不相似的类无法统一&#34;它们不仅保留了自己的实现,还保留了自己的接口。当您尝试统一使用它们时,代码会抛出异常。与将object
保持为IString
相比,通用界面并没有给你那么多 - 用户在拨打电话之前必须知道NotSupportedException
后面是什么类,否则他们可能会看到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
现在,单个实现将返回Singular
Category
中StringForm
的{{1}},而复数实现将返回IString
多个类别中的一个。试图在IString
的单个子类上设置复数类别可能仍然是一个错误,但是您可以通过将setter移动到类上来解决这个问题,从而无法在单个子类上调用具有类别的setter。 {{1}}。