2011-07-25 86 views
2

鑑於基本類型一如何將新派生類型添加到工廠模式?

三和派生類型 B: C:一個 d:一個

我有一個項目P. 我希望有一個列表來表示P.

A的出現

有一種從P中提取Bs的策略,我想要成爲B類的一部分。 有一種從P中提取Cs的策略,我想成爲C類的一部分。 等 我想要它們全部列入一個大名單。

我想稍後能夠添加一個類E:A,儘可能少觸摸。在接受P的實例作爲參數的情況下有一個虛擬的靜態工廠方法會很酷,它可以多態地運行派生類中的所有靜態重載,例如C中的重載將從P中提取Cs並將它們放入List中。 當然,在C#中不存在像虛擬靜態方法那樣的東西。

我不能立即看到如何實現這個,以便可以添加類D:A和E:A,而不用觸及基類或一些不斷更新的「God-method」工廠方法以及具體的依賴關係到每個派生類型。

這裏有點晚了,所以我可能會錯過一些明顯的東西。 您的想法?

編輯:

我的具體情況是,我具有由控制模塊一過程工廠控制系統。我希望能夠識別某些更高級別的構造,如控制循環,反饋調整等。識別和管理這些構造的邏輯特定於所討論的單個構造類型。簡而言之,我想捆綁用於識別和處理構造的代碼。

讓我們來考慮一個類比。我有一個文本文件。它裏面有一些單詞。 Word是「基本」類型「A」。文本文檔是「P」項目。我可以實現類型「名詞」和「動詞」。在文本中識別「名詞」的方式特定於「名詞」並且代碼應該。隨着越來越多的類型在文本中被實現並被識別,列表變得更長。

對我來說,是有意義的名詞類作爲內實現這一點:

static function IEnumerable<noun> IdentifyAll (P project) 

,並做了

CompleteWordList.AddRange(noun.IdentifyAll(p)); 

在初始化過程中,但是這創造依賴於特定的「名詞」從中央初始化/工廠方法鍵入。然後很難添加更多的詞類而不觸及它。在寫這篇文章時,我感覺自己有點偏向於MEF。

這是一個簡單的例子。也許「短語」或其他類似的基本類型比較合適,但現在必須做。

儘管這些項目是具有可檢查屬性的連接控制節點的網絡(而不是文本文檔),但它非常像解析器。如果有一些通用的解決方案可以避免,那將是一件好事。

+0

這可能是有趣的:http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

+0

你可以詳細闡述一下嗎?我在查看你的問題時遇到了一些麻煩。你似乎在問什麼,我很確定我可以寫,所以我可能會問題不對。 「項目」意味着什麼? 「列表」在哪裏?最重要的是,爲什麼任何方法都是靜態的? –

+0

謝謝。我已經添加了一些信息。我確實早些時候添加了該信息,但作爲對提供解決方案的第一個人的評論。他刪除了他的答案,因爲它不適用。但是在這樣做的時候,他也刪除了我的評論。 – Tormod

回答

1

好吧,我想我現在明白了。如果我明白,你想從A中得到一個類型的對象並確定它的實際類型(比如B),但沒有工廠知道如何將它歸類爲B。那麼你應該可以在將來引入任何數量的子類型A,而不必爲每種新類型修改工廠。

有人已知道如何從AB。如果不是工廠,那麼它本身必須是B。我看到你已經走上了這條道路,並且認爲「我需要一個虛擬工廠方法,以便A的每個子類型都可以提供規範來標識自己。」

正如你所說,虛擬靜態方法不存在,所以你不能這樣做你如何思考。但爲什麼不使用實例方法?

只要項目包含所有已知子類型的列表,它就可以遍歷這些類型,創建它們的實例並詢問它們「這個對象是你們中的一個嗎?」。如果它說「是」,那麼你可以問它「給我一個相當於這個基類型實例的實例」。 (這聽起來低效的;當然,在實踐中,你可以只保留每個類型的一個「工廠實例」活着的,所以你不必讓他們重新創建。)

使用像你的話比喻一個人爲的例子:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Drawing; 

interface IWord 
{ 
    bool IsTypeOf(IWord word); 
    string Text { get; set; } 
    IWord MakeFrom(IWord word); 
} 

// the base type 
class UntypedWord : IWord 
{ 
    public virtual string Text { get; set; } 
    public virtual bool IsTypeOf(IWord word) 
    { 
     throw new NotImplementedException(); 
    } 
    public virtual IWord MakeFrom(IWord word) 
    { 
     throw new NotImplementedException(); 
    } 
} 

// one specific subtype 
class ColorWord : UntypedWord 
{ 
    public Color Color { get; private set; } 

    public override bool IsTypeOf(IWord word) 
    { 
     return word.Text == "red" || word.Text == "green" || word.Text == "blue"; 
    } 

    public override IWord MakeFrom(IWord word) 
    { 
     var newMe = new ColorWord(); 
     newMe.Text = word.Text; 
     if (word.Text == "red") newMe.Color = Color.Red; 
     else if (word.Text == "blue") newMe.Color = Color.Blue; 
     else if (word.Text == "yellow") newMe.Color = Color.Yellow; 
     return newMe;    
    } 
} 

// another specific type 
class NumberWord : IWord // note: not an UntypedWord (see comments below) 
{ 
    public int Number { get; set; } 
    public string Text { get; set; } 

    public bool IsTypeOf(IWord word) 
    { 
     return word.Text == "one" || word.Text == "two" || word.Text == "three"; 
    } 

    public IWord MakeFrom(IWord word) 
    { 
     var newMe = new NumberWord(); 
     newMe.Text = word.Text; 
     if (word.Text == "one") newMe.Number = 1; 
     else if (word.Text == "two") newMe.Number = 2; 
     else if (word.Text == "three") newMe.Number = 3; 
     return newMe; 
    } 
} 


class WordList 
{ 
    Collection<Type> WordTypes = new Collection<Type>(); 
    Collection<IWord> UntypedWords = new Collection<IWord>(); 
    Dictionary<Type, Collection<IWord>> StronglyTypedWords = new Dictionary<Type, Collection<IWord>>(); 

    public void AddWordType<T>() where T : IWord 
    { 
     WordTypes.Add(typeof(T)); 

     if (!StronglyTypedWords.ContainsKey(typeof(T))) 
      StronglyTypedWords[typeof(T)] = new Collection<IWord>(); 
    } 

    public void Add(IWord word) 
    { 
     bool foundType = false; 
     foreach (Type type in WordTypes) 
     { 
      // in practice you'd cache these factories for efficiency 
      IWord instance = Activator.CreateInstance(type) as IWord; 
      if (instance.IsTypeOf(word)) 
      { 
       if (!StronglyTypedWords.ContainsKey(type)) 
        StronglyTypedWords[type] = new Collection<IWord>(); 

       StronglyTypedWords[type].Add(instance.MakeFrom(word)); 
       foundType = true; 
      } 
     } 
     if (!foundType) 
      UntypedWords.Add(word); 
    } 

    public int HowManyWordsOfType<T>() 
    { 
     if (StronglyTypedWords.ContainsKey(typeof(T))) 
      return StronglyTypedWords[typeof(T)].Count; 
     return 0; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var sentence = new WordList(); 
     sentence.AddWordType<ColorWord>(); 
     sentence.AddWordType<NumberWord>(); 

     sentence.Add(new UntypedWord { Text = "two" }); 
     sentence.Add(new UntypedWord { Text = "green" }); 
     sentence.Add(new UntypedWord { Text = "frogs" }); 
     sentence.Add(new UntypedWord { Text = "and" }); 
     sentence.Add(new UntypedWord { Text = "one" }); 
     sentence.Add(new UntypedWord { Text = "red" }); 
     sentence.Add(new UntypedWord { Text = "rose" }); 

     Console.WriteLine("color words: " + sentence.HowManyWordsOfType<ColorWord>()); 
     Console.WriteLine("number words: " + sentence.HowManyWordsOfType<NumberWord>()); 
    } 
}  

輸出:

color words: 2 
number words: 2 

現在,當你想添加一個新詞的類型,你必須添加的唯一代碼:

sentence.AddWordType<NewWordType>(); 

你會注意到ColorWordUntypedWord的子類型,但是NumberWord不是。只要Word實現IWord,Word類型就不必共享一個基本類型。

顯然這是一個荒謬的例子,但它顯示了每個子類型如何擁有基於公共超類型(或通用接口)的給定對象的屬性對自身進行分類的邏輯,並且它知道如何創建基於自身的實例在給定的對象上。

所以現在WordList(你的P)類永遠不需要更新,以適應新的單詞類型。你只需要在運行時告訴它所有的類型。

而你可以編寫你的IdentifyAll(WordList sentence)方法,只有它是一個實例方法而不是靜態方法。

+0

我剛從暑假回來,對當前的解決方案不滿意。乍一看,我認爲你的建議看起來很有趣。您已經實現了在代碼中刪除對具體類引用的需求的主要目的。如果「WordList」類包裝了一個List >,我想我可以達到相同的結果,但有一些事情我仍然在休假模式的頭腦不明白乍一看。我沒有得到UntypedWord和IWord分離的意義。也許它會改變,當我有我的第一杯咖啡。 – Tormod

+0

@Tormod:我沒有解釋清楚。所有單詞類型都必須實現IWord,但是從UntypedWord派生是可選的。從UntypedWord派生的單詞的潛在好處是它們可以從中繼承一些常用功能。爲了保持我的例子簡短,我沒有這樣做(除了Text屬性,這顯然是必要的)。只要它實現IWord,任何東西都可以添加到WordList中。 –

+0

這裏有足夠的價值,我會接受作爲答案。進一步深入挖掘我們的自動化系統的具體細節,以及Word的類比失效和問題難以被認爲是普遍的地方。非常感謝您的意見。 – Tormod

0

所以這裏真正的問題是如何在不知道派生類型的存在的情況下創建派生類型的實例;但是關於這個問題的重要之處在於邏輯會導致創建以前未知的派生類型。也就是說,必定有一些邏輯定義了一個新的狀態,以前未知的派生類型是合適的;但是,您希望工廠事先不知道該邏輯。

實際上,您的工廠成爲一個關聯繫統,它接受要滿足的條件與要創建的類型之間的關聯描述;那麼所有工廠都會讀取配置(或使用其注入配置)並執行定義的任何邏輯來確定要使用的創建代碼。它是一個作爲數據驅動對象的工廠。春天做了一些非常相似的事情; Spring的配置決定了對象和適合注入的類型之間的相互關係,而Spring只是按照它的要求進行操作。這種類型的系統非常複雜,但是非常具有可擴展性。

+0

謝謝。我同意並讚賞你的細分。我認爲MEF即使在運行時也完全解耦。但是,務實收益並不能保證。這只是工廠方法令人討厭的依賴。該系統是關於識別過程控制系統中某些類型的連接。我在另一評論中作了類比。如果你有進一步的想法,我是全部耳朵。 – Tormod