这是一个相当古老的问题,其答案已被接受,但为了详细说明所提供的答案并解决评论部分中出现的问题,正在提供此附加答案。
正如所提出的,这个问题有点不确定。当被问及在软件开发方面是否应该以某种方式完成某些事情时,该问题可以被理解为关于支配所讨论主题的底层设计原则的问题,当这些设计原则不统一时应该应用,或者两者兼而有之。为了帮助客观地讨论该主题,让我们依次考虑这两个方面。
创建构造函数以将值从一个对象映射到另一个对象的特定做法会在两个对象之间创建耦合。视图模型包含与系统内特定视图有关的属性和/或行为。由于此类对象的目的是对特定视图进行建模,因此封装用于从系统内的另一种类型初始化模型的内部状态/值的映射逻辑意味着视图模型现在包含可能因某种原因需要修改的代码除了视图建模方式的更改之外。此类更改可能会导致模型行为的其他方面受到不利影响,从而导致系统行为出现意外回归。管理系统内组件解耦以防止通过耦合多个关注点而导致行为意外回归的原则称为单一职责原则。
何时应用这些原则的问题有点困难。重要的是要记住,软件通常是在编写时考虑到一些目标(例如解决一些业务问题、促进娱乐或教育等),并且对于任何给定的软件来说最好的都是与手头的任务相关的。为作为特定公司的旗舰产品而创建的软件系统所做的选择可能与为解决当前问题而开发的系统所做的选择有很大不同。还需要考虑促进某些类型的解耦所需的工作范围。一些解耦技术相对容易整合,而另一些解耦技术可能更困难,甚至为初始实现以及添加到负责软件维护的团队中的每个新开发人员提供了逐步学习曲线。虽然没有任何启发式方法能够完美地做出此类决策,但测试驱动开发提出了在出现重复之前不引入抽象的启发式方法。例如,策略模式是一种遵守开放/封闭原则的优秀技术,该原则控制对象的设计,以允许它们在不同的场景中应用,而无需修改现有代码。然而,当遵循测试驱动开发实践时,在观察到第二个用例之前不会引入策略模式。通过遵循这种启发式,开发人员被迫将他们的精力限制在手头的任务上,只编写完成任务所需的代码而不重复,从而最大限度地减少浪费并最大化可维护性(通过最小化复杂性)。
尽管如此,软件工程既是一门科学,也是一门艺术。它是一门科学,因为有一些规则来控制为了达到某些目的可以做什么和不可以做什么,但它也是一门艺术,因为你做得越多,就会做得越好,并且需要做出明确的权衡最终必须主观地做出。例如,作为客户端软件开发人员,我通常从不参与生命周期较短的应用程序的设计和开发。因此,我不会等到看到重复才将基于约定的依赖项注入引入到我的应用程序中。在软件系统生命周期之初,在应用程序中引入一致使用依赖注入的成本比等到您开始感觉到需要它时要低得多。
关于在视图模型中添加映射代码的具体示例,虽然它确实将视图模型耦合到特定的域模型,但实际上我不认为这是一个大问题。视图模型不太可能与其他域模型一起使用,并且引入的代码类型(即映射)的性质通常不包含业务逻辑,因此这种 SRP 违规导致系统显着回归的可能性是远小于应用程序或域层的 SRP 违规。
也就是说,我不认为在构造函数中添加映射逻辑的过程可以节省任何时间。如果要创建一个单独的类来封装大多数语言中领域对象和视图模型之间的映射,我们只讨论额外的几行代码。这是实现上的差异:
// constructor
public ViewType(DomainType domainType) {
...
}
// mapper class
public class ViewTypeMapper {
public ViewType Map(DomainType domainType) {
...
}
}
因此,您要么执行 return new ViewType(domainType),要么执行 return new ViewTypeMapper().Map(domainType)。我只是看不出在这种情况下解耦会增加任何重要的工作。在大多数情况下,即使进行讨论,您也已经浪费了公司或客户的时间和金钱,因为与仅创建单独的类来表示相比,您最终总是会花费更长的时间来讨论它映射,或者如果您要继续设置 Automapper。