我不打算在代码所属的DDD中进行有关验证的辩论等,而是专注于一种可能的方法以及如何解决本地化问题。我在我的一个域对象(实体)上有以下行为(方法),它举例说明了该场景:
public void ClockIn()
{
if (WasTerminated)
{
throw new InvalidOperationException("Cannot clock-in a terminated employee.");
}
ClockedInAt = DateTime.Now;
:
}
如您所见,当调用ClockIn方法时,该方法会检查对象的状态以确保Employee尚未终止。如果Employee被终止,我们会抛出一个与“不要让您的实体进入无效状态”方法一致的异常。
我的问题是我需要本地化异常消息。这通常是(在此应用程序中)使用在需要访问其方法的类中使用MEF导入的应用程序服务(ILocalizationService)完成的。但是,与任何DI框架一样,只有在容器实例化对象时才会注入/导入依赖项。 DDD通常不是这种情况。
此外,我所学到的关于DDD的一切都说我们的域对象不应该有依赖关系,那些问题应该从域对象外部处理。如果是这种情况,我该如何进行本地化消息,例如上面显示的消息?
这不是一项新颖的要求,因为许多商业应用需要全球化/本地化。我很欣赏一些建议如何使这项工作仍然符合DDD的目标。
更新
我最初没有指出我们的本地化都是数据库驱动的,所以我们确实有一个本地化服务(通过可注入的ILocalizationService接口)。因此,使用Visual Studio提供的静态Resources类作为项目的一部分并不是一个可行的选择。
另一个更新
也许它会推动讨论,以表明该应用程序是一个RESTful服务应用程序。因此,客户端可以是一个简单的Web浏览器。因此,我不能编码任何期望调用者可以执行任何类型的本地化,代码映射等。当发生异常时(在这种方法中,尝试将域对象置于无效状态是一个例外),抛出异常并返回相应的HTTP状态代码以及异常消息,该异常消息应本地化到调用者的文化(Accept-Language)。
答案 0 :(得分:2)
不确定此响应对您有多大帮助,但本地化确实是一个前端问题。根据您的示例本地化异常消息并不常见,因为最终用户不应该看到技术细节,例如异常消息中描述的那些(并且即使不是他们的母语,任何将对您的异常进行故障排除的人也可能具有足够的英语水平)。
当然,如果有必要,您可以随时处理异常并向前端用户提供本地化,用户友好的消息。但是将其作为字体端关注点应该简化您的架构。
答案 1 :(得分:1)
正如Clafou所说,你不应该以任何方式使用异常将消息传递给UI。
如果你仍然坚持这样做,一个选择是抛出错误代码而不是消息
throw new InvalidOperationException("ERROR_TERMINATED_EMPLOYEE_CLOCKIN");
然后,当它发生时,做你需要做的任何事情(日志,查找本地化,等等)。
答案 2 :(得分:0)
如果本地化是域/应用程序的重要组成部分,您应该将其作为一等公民并注入其所属的任何位置。我不确定你的意思是“DDD说我们的域对象不应该有依赖” - 请解释一下。
答案 3 :(得分:0)
尝试避免向域模型对象添加内部依赖项是正确的。
更好的解决方案是处理服务方法中的操作,例如:
public class EmployeeServiceImpl implements EmployeeService {
public void ClockEmployeeIn(Employee employee) throws InvalidOperationException {
if (employee.isTerminated()) {
// Localize using a resource lookup code..
throw new InvalidOperationException("Error_Clockin_Employee_Terminated");
}
employee.setClockedInAt(DateTime.Now);
}
}
然后,您可以在进行clockin调用的位置使用DI框架注入服务,并使用该服务将域对象与业务逻辑的更改隔离开来。