Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Domain driven design 如何创建多语言域模型_Domain Driven Design_Multilingual - Fatal编程技术网

Domain driven design 如何创建多语言域模型

Domain driven design 如何创建多语言域模型,domain-driven-design,multilingual,Domain Driven Design,Multilingual,我正在使用领域驱动设计,我对我的领域模型有一个非常清晰的了解。它包含120多个类,并且非常稳定。我们将在.NET4和C#中实现它。问题是,我们需要多语言的模型;有些属性需要以多种语言存储。例如,Person类有一个类型为string的Position属性,该属性应以英语(例如“Library”)和西班牙语(例如“Bibliotecario”)存储一个值。此属性的getter应返回英语或西班牙语版本,具体取决于某些语言参数 现在开始我的问题。我不知道如何将其参数化。我列举了两种主要的方法: 使用属

我正在使用领域驱动设计,我对我的领域模型有一个非常清晰的了解。它包含120多个类,并且非常稳定。我们将在.NET4和C#中实现它。问题是,我们需要多语言的模型;有些属性需要以多种语言存储。例如,Person类有一个类型为
string
的Position属性,该属性应以英语(例如“Library”)和西班牙语(例如“Bibliotecario”)存储一个值。此属性的getter应返回英语或西班牙语版本,具体取决于某些语言参数

现在开始我的问题。我不知道如何将其参数化。我列举了两种主要的方法:

  • 使用属性集合。位置不是一个
    字符串
    ,而是一个
    字典
    ,它可以让客户通过语言检索此人的位置
  • 保留简单的标量属性,但根据全局已知的“当前语言”设置,使其返回(或设置)一种或另一种语言的值。客户端代码将设置工作语言,然后所有对象都将使用该语言设置和获取值
  • 选项1避免使用全局状态,但它会弄乱模型中几乎每个类的接口。另一方面,选项2的表达能力较差,因为如果不查看全局设置,就无法判断将使用哪种语言。此外,它还向全局设置上的每个类引入了依赖项

    请注意,我对数据库或ORM实现不感兴趣;我只在域模型级别工作

    那么,我有两个具体问题:

    • 要实现我的多语言域模型目标,哪一个是最好的选择(1或2)
    • 还有其他我没有考虑的选择吗?它们是什么
    多谢各位

    编辑。一些人认为这是一个与用户界面相关的问题,因此可以通过.NET中的全球化/本地化支持来解决。我不同意。UI本地化只有在您知道必须在编译时向用户显示的本地化文本时才起作用,但这不是我们的情况。我的问题涉及编译时未知的多语言数据,因为它将在运行时作为用户数据提供。这不是一个与UI相关的问题

    编辑2。请记住,Person.Position只是一个玩具示例来说明问题。这不是真实模型的一部分。不要试图批评它或改进它;那样做没有意义。我们的业务需求涉及许多属性,这些属性不能编码为枚举类型或类似类型,必须保持为自由文本。因此困难重重

    它包含120多个类,并且非常稳定

    与问题不直接相关,但您可能需要考虑域中多个有界上下文的存在。

    我同意Oded的观点,在您的场景中,语言是一个UI问题。当然,域可以通过C#和英语的组合来声明,它所表示的是抽象的。UI将使用-effective选项2处理语言

    具有Position属性的Person实体不控制用于表示位置的自然语言。您可能有一个用例,您希望用一种语言显示一个位置,而它最初存储在另一种语言中。在这种情况下,可以将转换器作为UI的一部分。这类似于将货币表示为金额和货币的一对,然后在货币之间进行转换

    编辑

    此属性的getter应返回英语或西班牙语 版本取决于某些语言参数


    什么决定了这个语言参数?什么负责确保Position以多种语言存储?或者翻译是在飞行中进行的?谁是该物业的客户?如果客户机确定语言参数,为什么客户机不能在不涉及域的情况下执行翻译?是否存在与多种语言相关的行为,或者这只是出于阅读目的?DDD的要点是提取您的核心行为域,并将与查询数据相关的方面转移到其他职责领域。例如,您可以使用访问具有特定语言的聚合的Position属性。

    域模型是一种抽象-它为世界的特定部分建模,它捕获域的概念

    该模型的存在使得开发人员可以用领域专家交流的方式进行代码交流——对相同的概念使用相同的名称

    现在,西班牙语专家和英语专家可能会对同一个概念使用不同的词,但概念本身是相同的(人们希望,尽管语言可能会模棱两可,人们并不总是以相同的方式理解同一个概念,但我离题了)

    代码应该为这些概念选择一种人类语言并坚持使用。模型完全没有理由为了表示一个概念而由不同的语言组成

    现在,您可能需要用他们的语言向用户显示应用程序数据和元数据,但概念没有改变

    在这方面,第二个选项是您应该做的事情-在.NET中,这通常是通过查看
    CurrentThread.CurrentCulture
    和/或
    CurrentThread.CurrentUICulture
    来完成的,并且使用它将包含本地化的资源。

    给出以下内容:

    一些用例涉及在所有的场景中设置对象的值 支持的语言;另一些则涉及到查看一个给定项目中的值 语言

    我建议两种选择都去。这意味着持有多语言内容的个人和所有类别都应将该内容保持在其状态,并且:

    • Position属性应设置/获取
      public enum Language {
          English,
          German
      }
      
      // all multilingual entity classes should derive from this one; this is practically a partly implemented observer
      public abstract class BaseMultilingualEntity
      {
          public Language CurrentLanguage { get; private set; }
      
          public void SetCurrentLanguage(Language lang)
          {
              this.CurrentLanguage = lang;
          }
      }
      
      // this is practically an observable and perhaps SRP is not fully respected here but you got the point i think
      public class UserSettings
      {
          private List<BaseMultilingualEntity> _multilingualEntities;
      
          public void SetCurrentLanguage(Language lang)
          {
              if (_multilingualEntities == null)
                  return;
      
              foreach (BaseMultilingualEntity multiLingualEntity in _multilingualEntities)
                  multiLingualEntity.SetCurrentLanguage(lang);
          }
      
          public void TrackMultilingualEntity(BaseMultilingualEntity multiLingualEntity)
          {
              if (_multilingualEntities == null)
                  _multilingualEntities = new List<BaseMultilingualEntity>();
      
              _multilingualEntities.Add(multiLingualEntity);
          }
      }
      
      // the Person entity class is a multilingual entity; the intention is to keep the XXXX with the XXXXInAllLanguages property in sync
      public class Person : BaseMultilingualEntity
      {
          public string Position
          {
              set
              {
                  _PositionInAllLanguages[this.CurrentLanguage] = value;
              }
              get
              {
                  return _PositionInAllLanguages[this.CurrentLanguage];
              }
          }
      
          private Dictionary<Language, string> _PositionInAllLanguages;
      
          public Dictionary<Language, string> PositionInAllLanguages {
              get
              {
                  return _PositionInAllLanguages;
              }
              set
              {
                  _PositionInAllLanguages = value;
              }
          }
      }
      
      public class Program
      {
          public static void Main()
          {
      
              UserSettings us = new UserSettings();
              us.SetCurrentLanguage(Language.English);
      
              Person person1 = new Person();
              us.TrackMultilingualEntity(person1);
      
              // use case: set position in all languages
              person1.PositionInAllLanguages = new Dictionary<Language, string> {
                  { Language.English, "Software Developer" }, 
                  { Language.German, "Software Entwikcler" }
              };
      
              // use case: display a person's position in the user language
              Console.WriteLine(person1.Position);
      
              // use case: switch language
              us.SetCurrentLanguage(Language.German);
              Console.WriteLine(person1.Position);
      
              // use case: set position in the current user's language
              person1.Position = "Software Entwickler";
      
              // use case: display a person's position in all languages
              foreach (Language lang in person1.PositionInAllLanguages.Keys)
                  Console.WriteLine(person1.PositionInAllLanguages[lang]);
      
      
              Console.ReadKey();
      
          }
      }
      
      public sealed class VATIN : IEquatable<VATIN> { // implementation here... }
      public sealed class Position : IEquatable<Position> { // implementation here... }
      public sealed class Person 
      { 
          // a few constructors here...
      
          // a Person's identifier from the domain expert, since it's an entity
          public VATIN Identifier { get { // implementation here } }
      
          // some more properties if you need them...
          public Position CurrentPosition { get { // implementation here } }
      
          // some commands
          public void PromoteTo(Position newPosition) { // implementation here }
      }
      public sealed class User
      {
          // <summary>Express the position provided according to the culture of the user.</summary>
          // <param name="position">Position to express.</param>
          // <exception cref="ArgumentNullException"><paramref name="position"/> is null.</exception>
          // <exception cref="UnknownPositionException"><paramref name="position"/> is unknown.</exception>
          public string Express(Position position) { // implementation here }
      
          // <summary>Returns the <see cref="Position"/> expressed from the user.</summary>
          // <param name="positionName">Name of the position in the culture of the user.</param>
          // <exception cref="ArgumentNullException"><paramref name="positionName"/> is null or empty.</exception>
          // <exception cref="UnknownPositionNameException"><paramref name="positionName"/> is unknown.</exception>
          public Position ParsePosition(string positionName) { // implementation here }
      }
      
      // IDomainDictionary would be resolved based on CurrentThread.CurrentUICulture
      var domainDict = container.Resolve<IDomainDictionary<Position>>();
      var position = person.Position;
      Debug.Writeline(domainDict.NameFor(position, pluralForm: 1));