Sergey Kucher
Sergey Kucher

Reputation: 4180

Design Patterns question

I have a following problem I want to solve ellegantly:

public interface IMyclass
{
} 
public class A
{
   public void Init(IMyclass class){?}
   public IMyclass CreateMyClass(){?}
}

At the start of the system I want to define dynamic type of IMyClass by using Init() and during the run of the system i would like to create new instances of the type I defined at init.

Notes:
1. IMyclass must be interface
2. The dynamic type of IMyclass known only at init (i have no constructor after :) )
3. I could do it using a reflection or definition method clone at IMyclass is there any better solutions?

Thank you.

Upvotes: 4

Views: 224

Answers (4)

Mike M
Mike M

Reputation: 1778

You'll need Reflection at some point due to visibility. If you can accept Reflection once up-front and not have to use it again, that would probably be ideal, yes?

You could put a getInstance() method on a hidden interface (located in the same package as IMyClass, MyClassImpl, and A, but not ClientOfA), and then pass a prototype of MyClassImpl to A.init().

// -- You wish you would have thought of the word prototypeable! ...maybe?
interface IMyClassPrototypeable extends IMyClass
{
 public IMyClass getInstance();
}

class MyClassImpl implements IMyClassPrototypeable // -- and IMyClass by extension.
{
 // -- Still not visible outside this package.
 public IMyClass getInstance()
 {
  return new MyClassImpl();
 }
}

class A
{
 private IMyClassPrototypeable prototype;

 // -- This method is package-private.
 void init( IMyClassPrototypeable prototype )
 {
  this.prototype = prototype;
 }

 public IMyClass createMyClass()
 {
  return prototype.getInstance();
 }
}

This solution would require Reflection to create the prototype instance of MyClassImpl, which could be done via Spring (or some other form of dependency injection). It uses the Prototype pattern, the Factory-method pattern, and readily supports the Singleton/Pool pattern, but remember that more design patterns used is not always better. In fact, it can make the design (and code) more complex and more difficult for a beginner to understand.

For the record, the only reason I would even think about advocating this solution is because it takes the reflection hit once, up front, rather than every time createMyClass() is called, which the original poster indicated he/she would be doing frequently.

Upvotes: 1

Kru
Kru

Reputation: 4235

This is a kind of dependency injection, you should read:

Basically, you have a class A that is populated with factories (or providers) at initialization. Then you use A instead of calling new.

A quick example:

interface Provider<V> {
   V instance(Object... args);
}
class Dispatch {
   // you can make a singleton out of this class
   Map<Class, Provider> map;
   <T> void register(Class<T> cl, Provider<? extends T> p) {
      // you can also bind to superclasses of cl
      map.put(cl, p);
   }
   <T, I extends T> void register(Class<T> cl, final Class<I> impl) {
      register(cl, new Provider<I>() {
         I instance(Object... args) {
            // this class should be refactored and put in a separate file
            // a constructor with arguments could be found based on types of args values
            // moreover, exceptions should be handled
            return impl.newInstace();
         }
      });
   }
   <T> T instance(Class<T> cl, Object... args) {
      return map.get(cl).instance(args);
   }
}

// usage
interface MyIf { ... }
class MyIfImpl implements MyIf { ... }

Dispatch d = new Dispatch();
d.register(MyIf.class, new Provider<MyIf>() {
   MyIf instance(Object... args) {
      return new MyIfImpl();
   }
});
// or just
d.register(MyIf.class, MyIfImpl.class);
MyIf i = d.instance(MyIf.class);

Edit: added register(Class, Class)

Upvotes: 2

David Harkness
David Harkness

Reputation: 36532

If you just want to instantiate the same class in CreateMyClass() without further configuration you can use reflection.

public class A
{
    private Class prototype;

    public void Init(IMyClass object) {
        this.prototype = object.getClass();
    }

    public IMyClass CreateMyClass() {
        return prototype.newInstance();
    }
}

I suspect you want more than this, and if so you'll need to explain how you want to use this. You may be looking for the Builder or Factory patterns.

Upvotes: 1

fearofawhackplanet
fearofawhackplanet

Reputation: 53388

You could pass a provider into class A

public class A
{ 
   IMyClassProvider _provider;

   public void Init(IMyClassProvider provider) 
   {
        _provider = provider; 
   }

   public IMyclass CreateMyClass()
   {
        return _provider.Create();
   }
}

Or maybe with a constructor delegate

public class A
{ 
   Func<IMyclass> _ctor;

   public void Init(Func<IMyclass> ctor) 
   {
        _ctor = ctor; 
   }

   public IMyclass CreateMyClass()
   {
        return _ctor();
   }
}

Note that both of these examples will blow up if Init has not been called before CreateMyClass, you would need some checking or better is doing your init in the constructor.

Have I understood the question correctly?

Upvotes: 2

Related Questions