2011-05-27 114 views
4

我有一个下面的问题我想ellegantly解决:设计模式质疑

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

在我想通过使用初始化(定义动态类型IMyClass系统的启动)和系统的运行过程中我想创建在init中定义的类型的新实例。

注:
1. IMyclass必须接口
2.动态类型IMyclass的仅在初始化已知的(我有后没有构造:))
3.我可以使用反射或定义做IMyclass的方法克隆是否有更好的解决方案?

谢谢。

+0

您可能想要注意您的编码约定是非标准的。我用于接口声明和方法上限通常不在Java中使用。 (有些人会争论接口之一,但Eclipse是我见过的唯一主要代码)。 – Robin 2011-05-27 18:58:14

回答

2

你可以通过一个提供商class A

public class A 
{ 
    IMyClassProvider _provider; 

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

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

或许与构造委托

public class A 
{ 
    Func<IMyclass> _ctor; 

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

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

注意,这两个示例将炸毁如果Init尚未CreateMyClass之前调用,你需要一些检查或更好的是在构造函数中做你的init。

我理解了这个问题吗?

+0

您能解释一下供应商或供应商使用代码是什么意思吗? – 2011-05-27 17:59:57

+0

我刚刚离开工作,稍后如果您还没有解决问题,请稍后更新 – fearofawhackplanet 2011-05-27 18:04:15

+0

是的,您正确理解问题。 – 2011-05-27 18:06:08

1

如果您只想在CreateMyClass()中实例化同一个类而无需进一步配置,则可以使用反射。

public class A 
{ 
    private Class prototype; 

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

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

我怀疑你想要比这更多,如果是这样,你需要解释你想如何使用它。您可能正在寻找BuilderFactory模式。

+0

谢谢你解决了这个问题。但是,你能告诉我性能问题吗 - 我经常创建的这个参数。如果它可能导致性能问题,你有没有涉及反射的解决方案? – 2011-05-27 18:10:17

+0

非常感谢! – 2011-05-27 18:51:06

+0

如果您想在运行时基于另一个类的对象动态实例化对象,则不需要。但是,如果你只有少数这样的班级为你做这个,那么你可以为每个班的恐惧动物小组网站写下个别的工厂。 – 2011-05-27 22:08:30

2

这是一种依赖注入,你应该阅读:

基本上,你有一个类A被填充工厂(或供应商)在初始化。然后,您使用A而不是致电new

一个简单的例子:

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); 

编辑: 添加register(Class, Class)

+0

非常感谢你,你有这个问题的优秀解决方案,我学会了很多,但我想避免使用反射。 – 2011-05-27 18:53:03

+0

如果你想不做反射,只需放下'register(Class,Class)'函数,它可能很方便,但不是很安全。 – Kru 2011-05-27 19:01:19

1

你会在因能见度某些时候需要反思。如果你能够预先接受Reflection并且不必再次使用它,那可能是理想的,是的?

你可以把一个隐藏式的接口(位于同一个包IMyClassMyClassImplA,但不ClientOfA)上getInstance()方法,然后通过一个原型的MyClassImplA.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(); 
} 
} 

该解决方案将需要思考创造MyClassImpl原型实例,它可以通过Spring来完成(或者依赖注入一些其他形式)。它使用Prototype模式,Factory方法模式,并且很容易支持Singleton/Pool模式,但请记住,使用的更多设计模式并不总是更好。事实上,它可以使设计(和代码)更复杂,更难以让初学者理解。

为了记录,我甚至会考虑提倡这种解决方案的唯一原因是因为它需要一次反射,而不是每次调用createMyClass(),原始海报表明他/她会做的经常。

+0

非常感谢你的解决方案! – 2011-05-27 20:57:19