Reputation: 4180
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
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
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
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
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