3

I need a pattern:

I'm using C#.

Say there are three actors; Jim, Pat, and Sally. Pat's job is to create an interface as a contract between Jim and Sally. Sally's job is to create a class that implements the interface and Jim's job is to write a class that consumes Sally's object.

Jim should not know about Sally's concrete object, only that it implements the common interface.

Pat needs to include in the contract a way for Jim to create an instance of Sally's concrete object but referenced as the interface.

There is no way to include a static method definition in either an interface or abstract class, so you can't do something like:

public interface IFoo
{
    public static IFoo CreateIFoo();
}

How can Pat write the contract to guarantee that Sally will create a method for Jim to create her concrete object referenced as the interface?

dtaylor
  • 997
  • 3
  • 10
  • 26
  • 2
    Factory pattern would probably help here. Either that, or you'd have to move the static method to a static helper class instead, but that wouldn't be in any way 'enforced' by the contract. – Patryk Ćwiek Jun 17 '13 at 18:37
  • Thanks "Trust me", You point out my dilemma, there is no way to enforce the factory as a static method in a helper class. – dtaylor Jun 17 '13 at 19:08

2 Answers2

1

If possible, ask for an instance of Sally:

class Jim 
{
    public Jim(Sally sally){ /* ... */ }
}

If, however, Jim needs to know WHEN to construct Sally, you can pass in a delegate:

class Jim
{
    private Func<Sally> _createSally.

    public Jim(Func<Sally> createSally)
    {
        _createSally = createSally;
    }

    public void ConsumeSally()
    {
        Sally sally = _createSally();
        /* ... */
    }
}

Simplest usage:

var jim = new Jim( () => new Sally() );

You don't need a class (Pat) to know how to instance sally, unless it really adds value to your code. Either way, you probably don't want Jim to know about Pat, so if Pat is needed this is what you'll want:

var jim = new Jim( () => Pat.GetSally() );
Ortiga
  • 8,455
  • 5
  • 42
  • 71
  • Thanks Andre, I'm afraid I'm a little confused by your terms. Assuming that you mean that "Jim" is the class that Jim wrote and "Sally" is the class that Sally wrote that implements IFoo, then "Jim" doesn't know about the class "Sally", only the interface IFoo. and "Jim" can't create "Sally" directly. Also, if you mean that "Pat" is the interface IFoo, you can't instantiate "Pat" to call GetSally(). There is no class "Pat". – dtaylor Jun 17 '13 at 19:24
  • What I'm saying is that a class should not know how to build it's dependency, and this includes not knowing the factory (Pat's class). If Jim (class that consumes the dependency) knows about Pat's (the factory), you'll have a Service Locator, which is considered an anti-pattern. – Ortiga Jun 18 '13 at 14:25
  • If a class really need to know when to build it's dependency (although this is not common), wrap it in a delegate or in a Lazy (C# 4+ only). – Ortiga Jun 18 '13 at 14:30
  • I'll try to improve my answer later, no time right now. Sorry. – Ortiga Jun 18 '13 at 14:30
0

Sounds like you need an abstract factory. In addition to IFoo, create an interface IFooFactory with the CreateFoo method. Give Jim an instance of an object that implements IFooFactory, and Jim would call the CreateFoo method. It could be either Sally or Pat's job to create the instance of the object that implements IFooFactory.

Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • Thanks Michael, So as I understand it there will be an additional interface such as: public interface IFooFactory { public IFoo CreateFoo(); } Doesn't this just push out the problem to the factory? How does Jim get the concrete object of the IFooFactory that Sally creates? – dtaylor Jun 17 '13 at 19:12
  • @dtaylor Sally has *some* kind of `FooFactory` - the factory that implements `IFooFactory`, which is bound by contract to create `IFoo` interfaces. You can create the factory in-place or inject the concrete factory, the main point here is: if Jim wants `IFoo` from Sally, he can get it by calling `IFooFactory.Create()`. – Patryk Ćwiek Jun 17 '13 at 20:20