2009-11-08 53 views
2

以下代碼是否有異味?我正在重構一些代碼,並且發現了這個循環關係,其中foo需要一個需要foo自己實現的接口的類。在其構造函數中使用C# - 它聞到了嗎?

在真實的代碼中,foo是一個Silverlight UserControl,ifoo有方法來做UI類型的事情,比如提出一個對話框(例如ShowMessage)。 needsAnIfoo類是一種(類型)控制器,只要它想要對UI執行任何操作,它就會使用ifoo接口。我有不同的「主題」UI實現iFoo,並在其構造函數中具有相同的鍋爐板代碼。 needsAnIfoo有各種屬性,這是UI的數據綁定(所以它也是一種模型)。

它編譯和運行良好,但我想知道是否有更好的方法。

那麼,它聞到了嗎?

interface ifoo 
    { 
     void bar(); 
    } 

    class foo : ifoo 
    { 
     readonly needsAnIfoo _needsAnIfoo; 
     internal foo() 
     { 
      _needsAnIfoo = new needsAnIfoo(this); 
     } 

     #region ifoo Members 
     public void bar() 
     { 
      throw new NotImplementedException(); 
     } 
     #endregion 
    } 

    class needsAnIfoo 
    { 
     readonly ifoo _myfoo; 
     public needsAnIfoo(ifoo foo) 
     { 
      _myfoo = foo; 
     } 
    } 

    static void Main(string[] args) 
    { 
     foo foo = new foo(); 
    } 

也許我應該新了needsAnIfoo,而沒有經過IFoo的構造函數,然後給它iFooInitialize方法。但是這看起來很奇怪:

foo foo = new foo(); 
    needsAnIfoo needsAnIfoo = new needsAnIfoo(foo); 
    foo.Initialise(needsAnIfoo); 

回答

1

聽起來像是一個建立模式的好地方,我會說Factory Method。

class Factory 
{ 
public: 
    virtual needsAnIfoo* Create(ProductId); 
}; 

needsAnIfoo* Factory::Create(ProductId id) 
{ 
    if (id == TYPE1) return new needsAnIfoo(ifooType1()); 
    if (id == TYPE2) return new needsAnIfoo(ifooType2()); 
    ... 
    return 0; 
} 

那麼你可以使用它像這樣:

Factory f = new Factory(); 
theme1 = f.Create(TYPE1); 
theme2 = f.Create(TYPE2); 

模式是你的朋友!

+0

感謝這個例子!我已經發布了我需要的一刻。 – 2009-11-10 01:42:24

+0

兄弟能夠得到upvote嗎? :)我會立刻評論你的東西... – Josh 2009-11-10 03:40:09

+0

最後upvoted你! (我正在審閱一些舊帖子和合並賬戶,所以我只記得這篇文章。) – 2011-01-09 20:51:03

1

它看起來不正確。聞起來很脆弱。

您是否考慮過查看構建器或工廠模式來創建相關對象並建立它們之間的關係?它可能會提供一個更安全的方式。

+0

是的,感謝工廠似乎要走的路。我已經組建了一個原型工廠,使我的「iFoos」 - 我即將發佈代碼。 – 2009-11-10 01:40:46

1

我同意生成器或工廠模式或類似模式會更好。提供的代碼不是非常可測試的,正如前面提到的那樣,這種代碼很脆弱,所以某種形式的依賴注入會很好。

使用的模式將取決於foo和needsAnIFoo如何使用對方。如果needsAnIFoo是主題,則foo是觀察者,而bar()是更新方法,您可能還需要考慮觀察者模式。

+0

好吧我已經重新安排了一些事情 - 我做了一個工廠,並且使用了一個事件作爲基礎觀察者模式。我會立即發佈我所做的。 – 2009-11-10 01:45:29

1

這聽起來像這可能是過於複雜,而你正在你的主題是控制器和有控制器(由兼具類實現的IFoo)

如果你分開的概念,您可能會收到更好的效果主題控制器,使控制器主題。然後,例如,當控制器執行某些操作時(例如彈出對話框),它會查看其主題以查找要使用的字體。

像這樣:

interface itheme {} // to describe properties of the theme 
class theme : itheme {}// a bunch of different themes, this previously would have been the "foo" 
class theme2 :itheme{} //etc. 

abstract class icontroller 
{ 
    protected icontroller(itheme ptheme) {theme = ptheme;} 

    protected itheme theme; 

    //function declarations 
    // .... 

} 
class control : icontroller {} // implements the icontrol functions. 
//not sure if you need more than one control implementation... 
// if not, i'd get rid of the icontrol interface. 


//use it by passing a theme into the controller constructor: 
icontroller myUIController = new control(new ClassicTheme()); 
+0

不要強調一點,但如果這是(新?)設計,它肯定應該使用構造模式(Factory Method似乎最有意義)。 – Josh 2009-11-08 23:42:29

+0

是的工廠方法會完成設計:) – dan 2009-11-09 00:55:31

0

我想明白這個問題一點點,但如果每個needsAnIfoo是依賴於只有一種類型的類和needsAnIfoo無助於本身似乎就可以使一個需要靜態類的需求擴展方法不需要將這個作爲構造函數arg傳遞。

extension method programming guide

0

這裏的工廠觀察員 - 似乎這樣的伎倆,避免newing「控制器」我的主題界面內。

interface ifoo 
    { 
     void bar(); 
    } 

    class foo : ifoo 
    { 
     public void bar() { Console.Write("do a foo type thing"); } 
    } 

    class foo2 : ifoo 
    { 
     public void bar() { Console.Write("do a foo2 type thing"); } 
    } 

    class needsAnIfoo 
    { 
     public event EventHandler SomethingIFooCanDealWith; 
     System.Threading.Timer _timer; 
     public needsAnIfoo() 
     { 
      _timer = new System.Threading.Timer(MakeFooDoSomething, null, 0, 1000); 
     } 

     void MakeFooDoSomething(Object state) 
     { 
      if (SomethingIFooCanDealWith != null) 
      { 
       SomethingIFooCanDealWith(this,EventArgs.Empty); 
      }; 
     } 
    } 

    class fooFactory 
    { 
     needsAnIfoo _needsAnIfoo = new needsAnIfoo(); 
     Dictionary<String, ifoo> _themedFoos = new Dictionary<string,ifoo>(); 
     ifoo _lastFoo = null; 

     public void RegisterFoo(String themeName, ifoo foo) 
     { 
      _themedFoos.Add(themeName, foo); 
     } 

     public ifoo GetThemedFoo(String theme) 
     { 
      if (_lastFoo != null) { _needsAnIfoo.SomethingIFooCanDealWith -= (sender, e) => _lastFoo.bar(); }; 
      ifoo newFoo = _themedFoos[theme]; 
      _needsAnIfoo.SomethingIFooCanDealWith += (sender, e) => newFoo.bar(); 
      _lastFoo = newFoo; 
      return newFoo; 
     } 
    } 

    static void Main(string[] args) 
    { 
     fooFactory factory = new fooFactory(); 
     factory.RegisterFoo("CompanyA", new foo()); 
     factory.RegisterFoo("CompanyB", new foo2()); 

     ifoo foo = factory.GetThemedFoo("CompanyA"); 
     Console.Write("Press key to switch theme"); 
     Console.ReadKey(); 

     foo = factory.GetThemedFoo("CompanyB"); 
     Console.ReadKey(); 
    } 
+1

這不是一個真正的工廠 - 這更類似於Gamma等人提出的'Flyweight Factory'。人。 (P198)。教科書工廠模式用於構建新的對象;不提供對現有對象的引用。 這就是說,模式是指導方針。我相信這個片段與原來的片段相比有了很大的改進,並且它適用於主題之間的實時切換(而不是在啓動時選擇,這對教科書工廠來說更適合)。 – Josh 2009-11-10 03:46:42

+0

對不起 - 這是一家工廠;只是不是教科書工廠。沒有任何不好的地方;只是澄清工廠模式的意圖! :d – Josh 2009-11-10 03:47:26