我应该使用什么样的创作模式?

我的课程有两节课; 两者都来自相同的基类。

class A : MyBase { internal A(InitVal initVal) } class B : MyBase { internal B(InitVal initVal) } 

InitVal是另一个通过构造函数注入的类。 此课程供内部使用。 由于内部构造函数,用户无法直接创建A类和BA实例。 相反,我创建了创建这些对象的方法。

 class Initiator { InitVal initVal; public T CreateObject(ObjectInstance objectInstance) where T : MyBase { MyBase myBase = null; switch(objectInstance) { case ObjectInstance.A: myBase = new A(initVal); break; case ObjectInstance.B: myBase = new B(initVal); break; } return (T)myBase; } ... } 

ObjectInstance是上面代码中的枚举。

这没有问题,但我相信你以前从未见过如此丑陋的代码。

请建议我应该使用的创作模式。 我想删除ObjectInstance枚举而不更改function。 它会清理很多。

我尝试了在dotfactory上提到的Creational Patterns 。 在这种情况下, Factory MethodAbstract Factory看起来不合适。

我的代码虽然看起来很难看,但阅读和理解起来非常简单。 我尝试实现上面提到的模式,这会增加代码复杂性 所以这也是我选择答案时的标准。

除了Initiator类之外,我无法更改代码中的任何内容。 我无法访问所有其他类进行编辑。

编辑1:为什么上面的代码在我的视图中是丑陋的

1)在调用CreateObject方法时,用户必须指定对象的类型两次。

 A a = initiator.CreateObject(ObjectInstance.A); 

首先是T通用值,第二个是枚举值。 我想避免这个。

2)由于用户必须指定两次对象类型,因此存在错误的可能性。

 A a = initiator.CreateObject(ObjectInstance.B); 

在上面的代码中,枚举值和通用值是不同的。 这是不允许的,这将是一个问题。 用我的代码,我无法避免这种情况。

这就是为什么; 我正在寻找适合我的情况的模式,而不会增加复杂性。

如果我以某种方式删除枚举的必要性,代码将会好很多。 如果我可以将CreateObject签名更改为以下内容,那将会更好。

 public T CreateObject() where T : MyBase 

但是,我不确定如何实现此方法来创建适当的实例。

它并不像我看到你试图使这个通用的任何优势。 您需要知道调用站点返回值的具体类型。

因此,为什么不保持简单,只是这样做?

 public class Initiator { InitVal initVal; public A CreateA() { return new A(initVal); } public B CreateB() { return new B(initVal); } } 

当您将该方法指定为通用方法时,我希望您可能实际上知道在编译期间您想要获得的类型..所以我会选择这样的方法:

 class Initiator { public T CreateObject(ObjectInstance objectInstance) where T : MyBase, new() { T newInstance = new T(); newInstance.Value = initVal; return newInstance; } ... } 

现在你可以称之为:

 A myAInstance = initiator.CreateObject(); MyBase myAInstance = initiator.CreateObject(); //this also works 

要使其工作,您需要在类中指定内部无参数构造函数 ,并指定Value属性的接口或现在在当前构造函数中设置的任何内容。

 class MyBase{ InitVal Value { get; set;} //this allows construction of the object with parameterless constructor ... } 

这不仅更干净,更短,而且更不容易出错,因为每次添加新类型时都不需要编辑枚举和方法体。 但是,它为子类型特定逻辑提供了较少的灵活性。

注意:如果你真的想拥有带有参数的构造函数,你仍然可以使用这种方法但是你需要使用reflection (检查Activator)或lambdas。

当然,如果您可以在编译期间决定类型,或者您只想将此分区委托给第三方库,那么这只是有意义的,例如:

 switch(chosenType){ case ObjectInstance.A: instance = initiator.CreateObject(); ... 

否则,只需保持原样,或多或少的FactoryMethod模式,它就可以完成工作。 只是它的通用参数……似乎没那么无用。 我会删除它并将返回类型更改为MyBase,因为用户无论如何都无法指定T.

最后一个选项是简单地为每种类型创建一个单独的方法 ,这是干净,灵活,提供了很多自定义选项,但是如果你需要重复很多共享逻辑并且你需要为每个添加一个新的共享逻辑很糟糕下一个类型。 只是:

 A CreateObjectA(InitVal initValue){ return new A(initValue); } B CreateObjectB(InitVal initValue){ ... 

你的代码的一个明显问题是枚举,这是不必要的,因为typeof(T)已经为你提供了合适的类型:

 class Initiator { readonly Dictionary> _dict = new Dictionary>(); internal Initiator(InitVal initVal) { // initialize your "service locator". // it's cool that different types can have different constructors, // and people who call CreateObject don't need to know this. _dict[typeof(A)] = (Func)(() => new A(initVal)); _dict[typeof(B)] = (Func)(() => new B(initVal, someOtherStuff)); } public T CreateObject() where T : MyBase { var ctor = _dict[typeof(T)]; return (T)ctor(); } } 

或者,如果您不知道类型,则可以传递枚举,但是返回类型应该是接口/基类(最好是接口):

 // this is more likely, you probably don't need a generic method public IMyBase CreateObject(ObjectInstance objectInstance) { // the dictionary would map enum value to Func, of course var ctor = _dict[objectInstance]; return ctor(); } 

现在你有一个简单的“穷人”DI类叫做Initiator ,所以我想知道你的DI框架(注入InitVal )是否也可以注入AB实例。 这可能是真的,因为DI纯粹主义者会告诉你工厂里没有地方,你的代码中也没有new关键字。

顺便说一句, ObjectInstance是一个非常非常糟糕的枚举名称。

我是按照以下方式做到的:

 class A : IMyType { internal A(InitVal initVal) } class B : IMyType { internal B(InitVal initVal) } class Initiator { InitVal initVal = .....; public T CreateObject() where T : IMyType { IMyType myType = null; if(typeof(T) == typeof(A)) myType = new A(initVal); else if(typeof(T) == typeof(B)) myType = new B(initVal); else throw new MyException("Type is not configured."); return (T)myType; } ... } 

这解决了我在问题中提到的问题。 但是,它会产生新的问题。 这违反了SOLID的开放原则 。 如果有的话,最后一个块处理手动错误。 无论如何,它只适用于我的具体情况; 一般不推荐