views:

39

answers:

5

Example 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();
}

Example 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();
}

Which is the better option, example A, B, neither, or "it depends"?

A: 

The problem with A is that you have to implement every method of IFoo in Foo. That is not a big deal if there are only a couple, but is a pain if there are dozens of them. If you are working with a language that supports factory methods, such as Curl, then you could put a factory method in 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}
Christopher Barber
Interesting answer, however I'm using C#, but factory is indeed still an option. I wonder if there are any clear disadvantages of using a factory in this scenario.
nbolton
A: 

Interfaces are used when it is possible that multiple implementations of a single functional set may exist. This sounds as though it applies to your particular scenario.

In terms of your examples, I would definitely roll with B, it is easier to maintain. A embeds too much common logic [ie platform detection] within individual classes [and/or methods]. If you are to build your own Factory class, try to generalize it [through a generic Resolve<IType> () method or something], as opposed to a method\class per interface.

For instance,

// 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;
    }
}

However, rather than implement your own Factory pattern, you may wish to investigate alternative implementations, such as MS's Unity2.0 or Castle Windsor's CastleWindsorContainer. These are easy to configure and consume.

Ideally,

// 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 { }

Oh, suppose I ought to shout out to Ninject and StructureMap too. I am just not as familiar with these as with Unity or CastleWindsor.

johnny g
A: 

If you ask me B is way better - since Foo itself does not need to do any switching on platform. Why does that matter? Well, since you probably want to test all components separately - Foo with a 'test' IFoo, FooPlatformA separately on platform A and FooPlatformB on platform B. If you stick the choice inside Foo you need to test Foo on both A and B, not only the different IFoos. Makes the components more coupled for no apparent reason.

disown
+5  A: 

I would say that your explicit factory option (option B) is generally better.

In your first example your Foo class is effectively doing two jobs, it's a factory and it's a proxy. Two jobs, one class, makes me uneasy.

Your second option puts a little more responsibility on the client: they need to know to use the factory, but this is such a widely used idiom that I think it's not hard to understand.

djna
Great answer. To be honest, 4 functions tipped me over the edge. Re-implementing my proxy/wrapper/factory model into a nice clean factory as we speak. On a related note, please could you pass comment on the CArch class in synergy (it demonstrates something similar to example A): http://synergy2.svn.sourceforge.net/viewvc/synergy2/trunk/lib/arch/CArch.cpp?view=markup
nbolton
Thanks. I view that example as very much focusing on creating a proxy. From the client's point of view a simple architecture object is used, we are expending the effort of creating those proxy methods in order to make the client's life simple. The factory method is trivial. Should we start to have many variations of the factory logic, and especially if we would benefit from an Abstract Factory pattern then I would prefer to refactor that factory code. Right now, we are giving greatest weight to client simplicity.
djna
A: 

The factory is a cleaner solution as you do not have implement each member of the interface in the wrapper class Foo : IFoo. Imagine, each time you modify the IFoo interface you would need update the wrapper. When programming, depending on your goals, try to consider maintainability as much as possible.

Are all 'platforms' available or only one of them? Is the only difference between the platforms is logic? Thinking from a game developer perspective I would use #defines to implement this.

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

HTH,

Dennis Roche
Also whilst on the topic of best-practices; I understand that using Foo, Bar, FooBar is a common programming paradigm but honestly had to read your example several times to understand your intention. :|
Dennis Roche
Hmm, I see. I will bare this in mind in future.
nbolton