簡體   English   中英

我應該使用什么樣的創作模式?

[英]What creational pattern I should use?

我的課程有兩節課; 兩者都來自相同的基類。

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

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

InitVal是另一個通過構造函數注入的類。 此課程供內部使用。 由於內部構造函數,用戶無法直接創建A類和BA實例。 相反,我創建了創建這些對象的方法。

class Initiator
{
    InitVal initVal;

    public T CreateObject<T>(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枚舉而不更改功能。 它會清理很多。

我嘗試了在dotfactory上提到的Creational Patterns 在這種情況下, Factory MethodAbstract Factory看起來不合適。

我的代碼雖然看起來很難看,但閱讀和理解起來非常簡單。 我嘗試實現上面提到的模式,這增加了代碼復雜性 所以這也是我選擇答案時的標准。

除了Initiator類之外,我無法更改代碼中的任何內容。 我無法訪問所有其他類進行編輯。

編輯1:為什么上面的代碼在我的視圖中是丑陋的

1)在調用CreateObject方法時,用戶必須指定對象的類型兩次。

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

首先是T通用值,第二是枚舉值。 我想避免這種情況。

2)由於用戶必須指定兩次對象類型,因此存在錯誤的可能性。

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

在上面的代碼中,枚舉值和通用值是不同的。 這是不允許的,這將是一個問題。 用我的代碼,我無法避免這種情況。

這就是為什么; 我正在尋找適合我的情況的模式,而不會增加復雜性。

如果我以某種方式刪除枚舉的必要性,代碼將會好很多。 如果我可以將CreateObject簽名更改為以下內容,那將會更好。

public T CreateObject<T>() 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<T>(ObjectInstance objectInstance) where T : MyBase, new()
    {
        T newInstance = new T();
        newInstance.Value = initVal;

        return newInstance;
    }
...
}

現在你可以稱之為:

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

要使其工作,您需要在類中指定一個內部無參數構造函數 ,並指定Value屬性的接口或現在在當前構造函數中設置的任何內容。

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

這不僅更干凈,更短,而且更不容易出錯,因為每次添加新類型時都不需要編輯枚舉和方法體。 但是,它為子類型特定邏輯提供了較少的靈活性。

注意:如果你真的想擁有帶有參數的構造函數,你仍然可以采用這種方法,但你需要使用反射 (檢查Activator)或lambdas。

當然,如果您可以在編譯期間決定類型,或者您只是想將此分區委托給第三方庫,那么這只是有意義的,例如:

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

否則,只需保持原樣,或多或少的FactoryMethod模式,它就可以完成工作。 只是它中的通用參數......似乎沒那么無用。 我會刪除它並將返回類型更改為MyBase,因為用戶無論如何都無法指定T.

最后一個選項是簡單地為每種類型創建一個單獨的方法 ,這是干凈,靈活,提供了很多自定義選項,但是如果你需要重復很多共享邏輯並且你需要為每個添加一個新的共享邏輯很糟糕下一個類型。 只是:

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

你的代碼的一個明顯問題是枚舉,這是不必要的,因為typeof(T)已經為你提供了合適的類型:

class Initiator
{
    readonly Dictionary<Type, Func<MyBase>> _dict = new Dictionary<Type, Func<MyBase>>();

    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<MyBase>)(() => new A(initVal));
        _dict[typeof(B)] = (Func<MyBase>)(() => new B(initVal, someOtherStuff));
    }

    public T CreateObject<T>() 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<IMyBase>, 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<T>() 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的開放原則 最后else塊處理手冊錯誤(如有)。 無論如何,它只適用於我的具體情況; 一般不推薦

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM