我应该使用接口或工厂(和接口)进行跨平台实现吗?

时间:2010-06-08 14:02:28

标签: interface cross-platform factory

示例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,既不是,也不是“它取决于”?

5 个答案:

答案 0 :(得分:5)

我会说明确的工厂选项(选项B)通常更好。

在你的第一个例子中,你的Foo类实际上是在做两个工作,它是一个工厂,它是一个代理。两个工作,一个班,让我感到不安。

你的第二个选择对客户承担更多的责任:他们需要知道使用工厂,但这是一个广泛使用的习语,我认为这不难理解。

答案 1 :(得分:0)

A的问题是你必须在Foo中实现IFoo的每个方法。如果只有一对夫妇,这不是什么大不了的事,但如果有几个人就会痛苦。如果您正在使用支持工厂方法的语言,例如Curl,那么您可以在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}

答案 2 :(得分:0)

当可能存在单个功能集的多个实现时,使用接口。这听起来好像适用于您的特定情况。

就你的例子而言,我肯定会用B滚动,它更容易维护。 A在各个类[和/或方法]中嵌入了太多共同的逻辑[即平台检测]。如果要构建自己的Factory类,请尝试[通过通用Resolve<IType> ()方法或其他方式]对其进行概括,而不是每个接口的方法类。

例如,

// 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或Castle Windsor的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不熟悉这些。

答案 3 :(得分:0)

如果你问我B更好 - 因为Foo本身不需要在平台上进行任何切换。为什么这么重要?好吧,因为你可能想要分别测试所有组件 - 在平台A上分别测试'test'IFoo,FooPlatformA和FooPlatformB,如果你坚持选择Foo,你需要在A和B上测试Foo,而不是只有不同的IFoos。无缘无故地使组件更加耦合。

答案 4 :(得分: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,