Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.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
C# 模式来创建类型取决于另一个对象类型的新对象?_C#_Design Patterns - Fatal编程技术网

C# 模式来创建类型取决于另一个对象类型的新对象?

C# 模式来创建类型取决于另一个对象类型的新对象?,c#,design-patterns,C#,Design Patterns,我有这样的想法: interface IProduct { } class ProductA : IProduct { } class ProductB : IProduct { } .... interface IViewModel { } class ProductAViewModel : IViewModel { } class ProductBViewModel : IViewModel { } IViewModel CreateViewModel(IProduct pr

我有这样的想法:

interface IProduct { }

class ProductA : IProduct { }

class ProductB : IProduct { }

....

interface IViewModel { }

class ProductAViewModel : IViewModel { }

class ProductBViewModel : IViewModel { }

IViewModel CreateViewModel(IProduct product)
{
    var vmType = Assembly.getTypes().SingleOrDefault(x => x.Name == $"{product.GetType().Name}ViewModel");

    // Create instance of vmType and perform mapping of properties between product and vm using reflection based on name convention. Automapper can do this for you as well.
    }
现在,我希望能够创建ViewModels的实例,而不知道产品的实际类型:

IProduct prod = new ProductA();
IViewModel vm = someFactoryOrBuilderObject.CreateViewModel(prod);
// real type of vm depends on the product's type
// if prod is ProductA, vm must be ProductAViewModel
...
DisplayViewModel(VM); // working with VM as IViewModel (regardless of it's real type)
目标:

  • 必须在运行时解析ViewModel的类型

  • 向我的应用程序添加新产品和viewmodels不需要对现有代码进行任何更改

实现此功能的最佳方式是什么? 有一些明显的方法,但并不令人满意:

  • 创建类似映射(字典)的类型(productTypevmType)。但当我想添加更多产品时,我必须更改此地图
  • 在每个产品类中创建一个工厂方法,如GetViewModel()。但这违反了SOLID的SRP
  • 创建工厂或建筑商。但是这些模式不能满足我的需求

如果您只想在运行时执行此操作,我看到的唯一选项是按名称约定进行映射。在CreateViewModel中,您将搜索如下内容:

interface IProduct { }

class ProductA : IProduct { }

class ProductB : IProduct { }

....

interface IViewModel { }

class ProductAViewModel : IViewModel { }

class ProductBViewModel : IViewModel { }

IViewModel CreateViewModel(IProduct product)
{
    var vmType = Assembly.getTypes().SingleOrDefault(x => x.Name == $"{product.GetType().Name}ViewModel");

    // Create instance of vmType and perform mapping of properties between product and vm using reflection based on name convention. Automapper can do this for you as well.
    }

警告:这可能不是一个好的设计模式。

实际上,依赖链应该是
视图
=>
视图模型
=>
模型
=>
表示“依赖”)。
模型
不应知道任何有关
视图模型
的信息(即,通过属性,在下面的代码中)

下面的答案只是对你在问题中提出的要求的一种变通


我认为没有真正“干净”的方法可以做到这一点而不使用反射。但是,我们可以使用反射(使用反射的代价是:)使代码的其余部分变得干净

我现在提出一个使用属性的解决方案

记住:只有当每个
ViewModel
类都有一个公共构造函数,并且该类将一个
产品
对象作为参数时,此方法才有效
如果不是,Varun的解决方案会更好(在这种情况下,您仍然需要一个映射函数)

要使用它,请在
产品
类之前添加一个
UseViewModel(typeof(ViewModelForThisProductType))
。比如:

[UseViewModel(typeof(ProductAViewModel))]
class ProductA : IProduct { }

[UseViewModel(typeof(ProductBViewModel))]
class ProductB : IProduct { }
您的
ViewModel
类应该如下所示:

class ProductAViewModel : IViewModel {
    //You can use both IProduct or the derived type (i.e ProductA) as the constructor param
    public ProductAViewModel(ProductA a)
    {

    }
}

class ProductBViewModel : IViewModel {
    public ProductBViewModel(IProduct b)
    {

    }
}

无论如何,在某些地方,您需要“链接”viewmodel和product。恐怕您是对的:(.我只是想坚持SOLID的OCP。如果你想要一个好的模式,那么你可能想借鉴一下Windows Shell命名空间扩展和Microsoft管理控制台,看看它们在幕后是如何工作的。不管怎样,你提出的设计可能是一个糟糕的设计。当你的模型需要出现在许多不同类型的V中时会发生什么iewModels?我可能有一个
患者
需要同时出现在
人口统计视图模型
处方视图模型
中。很少有一个实体类型与视图模型的比例为1:1。但是,视图和视图模型的情况并非如此。我知道有一些框架可以从虚拟机或虚拟机自动确定Vsa.也许这就是你所想的?我也在想反射,但这是我最不想在我的案例中使用的东西。我想要一些“干净”的架构。@Vladimir所有使用反射的“干净”架构框架和库。我可以看出这有两个错误。1)如果一个模型需要在多个ViewModel中显示,会发生什么情况?模型和虚拟机之间很少有1:1的比例2)您纯粹为了虚拟机的利益而用属性污染模型。在规范数据模型系统中,WCF或网络层可能不关心这些attributes@MickyD我同意这是一个糟糕的设计。视图应该知道它们的视图模型,视图模型应该知道它们的模型,而不是相反。但这正是OP所要求的。我将编辑答案,以表明这不是一个好的设计。这是真的,这是OP要求的,是一个合理的解决方案+1.