2010-06-08 15 views
5

實施例A:我應該使用接口還是工廠(和接口)進行跨平臺實施?

// pseudo code 
interface IFoo { 
    void bar(); 
} 

class FooPlatformA : IFoo { 
    void bar() { /* ... */ } 
} 

class FooPlatformB : IFoo { 
    void bar() { /* ... */ } 
} 

class Foo : IFoo { 
    IFoo m_foo; 
    public Foo() { 
     if (detectPlatformA()} { 
      m_foo = new FooPlatformA(); 
     } else { 
      m_foo = new FooPlatformB(); 
     } 
    } 

    // wrapper function - downside is we'd have to create one 
    // of these for each function, which doesn't seem right. 
    void bar() { 
     m_foo.bar(); 
    } 
} 

Main() { 
    Foo foo = new Foo(); 
    foo.bar(); 
} 

實施例B:

// pseudo code 
interface IFoo { 
    void bar(); 
} 

class FooPlatformA : IFoo { 
    void bar() { /* ... */ } 
} 

class FooPlatformB : IFoo { 
    void bar() { /* ... */ } 
} 

class FooFactory { 
    IFoo newFoo() { 
     if (detectPlatformA()} { 
      return new FooPlatformA(); 
     } else { 
      return new FooPlatformB(); 
     } 
    } 
} 

Main() { 
    FooFactory factory = new FooFactory(); 
    IFoo foo = factory.newFoo(); 
    foo.bar(); 
} 

哪個是更好的選擇,例如A,B,既沒有,或 「這取決於」?

回答

0

A的問題是你必須在Foo中實現IFoo的每個方法。如果只有一對夫婦,這並不是什麼大不了的事情,但如果有幾十個這樣的話,那將是一件痛苦的事情。如果您正在使用支持工廠方法,如捲曲語言的工作,那麼你可以把一個工廠方法的IFoo:

{define-class abstract IFoo 
    {method abstract {bar}:void} 
    {factory {default}:{this-class} 
     {if platformA? then 
      {return {FooPlatformA}} 
     else 
      {return {FooPlatformB}} 
     } 
    } 
} 

{define-class FooPlatformA {inherits IFoo} 
     {method {bar}:void} 
} 

... 

def foo = {IFoo} 
{foo.bar} 
+0

有趣的答案,但我使用C#,但工廠確實仍是一個選項。我想知道在這種情況下使用工廠是否有明顯的缺點。 – 2010-06-08 14:13:58

0

接口使用時,它可能是一個單一的功能集的多種實現可能存在。這聽起來好像適用於您的特定場景。

就你的例子而言,我肯定會用B來滾動,這樣更容易維護。在單獨的類[和/或方法]中嵌入了太多的通用邏輯[即平臺檢測]。如果要構建自己的Factory類,請嘗試將其推廣[通過通用的Resolve<IType>()方法或其他],而不是每個接口的方法\ class。

例如,

// i called it a "container" because it "contains" implementations 
// or instantiation methods for requested types - but it *is* a 
// factory. 
public class Container 
{ 
    // "resolves" correct implementation for a requested type. 
    public IType Resolve<IType>() 
    { 
     IType typed = default (IType); 
     if (isPlatformA) 
     { 
      // switch or function map on IType for correct 
      // platform A implementation 
     } 
     else if (isPlatformB) 
     { 
      // switch or function map on IType for correct 
      // platform B implementation 
     } 
     else 
     { 
      // throw NotSupportedException 
     } 
     return typed; 
    } 
} 

然而,而不是實現自己的工廠模式,你不妨研究替代性的實現,如MS的Unity2.0或溫莎城堡的CastleWindsorContainer。這些配置和使用都很容易。

理想的情況下,

// use an interface to isolate *your* code from actual 
// implementation, which could change depending on your needs, 
// for instance if you "roll your own" or switch between Unity, 
// Castle Windsor, or some other vendor 
public interface IContainer 
{ 
    IType Resolve<IType>(); 
} 

// custom "roll your own" container, similar to above, 
public class Container : IContainer { } 

// delegates to an instance of a Unity container, 
public class UnityContainer : IContainer { } 

// delegates to an instance of a CastleWindsorContainer, 
public class CastleWindsorContainer : IContainer { } 

哦,想我應該喊出NinjectStructureMap了。我並不像Unity或CastleWindsor那樣熟悉這些。

0

如果你問我B更好 - 因爲Foo本身不需要在平臺上進行任何切換。爲什麼這很重要?那麼,因爲你可能想單獨測試所有組件 - Foo使用'測試'IFoo,FooPlatformA分別在平臺A和FooPlatformB在平臺B上。如果你在Foo內部選擇了,你需要在A和B上測試Foo,而不是隻有不同的IFOOS。無明顯原因使組件更加耦合。

5

我會說你的顯式工廠選項(選項B)通常更好。

在你的第一個例子中,你的Foo類有效地完成了兩個工作,它是一個工廠,它是一個代理。兩個工作,一個班,讓我感到不安。

你的第二個選擇會給客戶多一點責任:他們需要知道使用工廠,但這是一個廣泛使用的習慣用法,我認爲這不難理解。

+0

很棒的回答。說實話,有4項功能讓我感受到了這個優勢。當我們說話時,重新將我的代理/包裝/工廠模型實施到一個漂亮的乾淨工廠。在相關說明中,請您協同評論CArch類(它演示類似於示例A的內容):http://synergy2.svn.sourceforge.net/viewvc/synergy2/trunk/lib/arch/CArch。 cpp?view =標記 – 2010-06-08 14:36:03

+0

謝謝。我認爲這個例子非常專注於創建代理。從客戶的角度來看,使用了一個簡單的架構對象,我們正在努力創建這些代理方法,以使客戶的生活變得簡單。工廠方法是微不足道的。我們是否應該開始有許多工廠邏輯的變體,特別是如果我們能從抽象工廠模式中受益,那麼我寧願重構那個工廠代碼。現在,我們正在最大限度地重視客戶的簡單性。 – djna 2010-06-09 07:00:08

0

工廠是一個更清潔的解決方案,因爲您沒有實現包裝器中的每個接口成員class Foo : IFoo。想象一下,每次修改IFoo接口時,都需要更新包裝器。在編程時,根據您的目標,儘可能考慮可維護性。

是否有所有'平臺'或只有其中一個?平臺之間唯一的區別是邏輯嗎?從遊戲開發者的角度思考,我會使用#defines來實現這一點。

class Platform : IPlatform 
{ 
    void Update() 
    { 
#if PLATFORM_A 
     * ... Logic for platform A */ 
#elif PLATFORM_B 
     * ... Logic for platform A */ 
#endif 
    } 
} 

HTH,

+1

同時關於最佳實踐的話題;我明白使用Foo,Bar,FooBar是一種常見的編程範例,但是爲了理解你的意圖,老實說,必須多次閱讀你的例子。 :| – Dennis 2010-06-08 14:24:53

+0

嗯,我明白了。將來我會記住這一點。 – 2010-06-08 14:41:02