简体   繁体   English

设计模式问题

[英]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.在系统启动时,我想通过使用 Init() 来定义 IMyClass 的动态类型,并且在系统运行期间,我想创建我在 init 中定义的类型的新实例。

Notes:笔记:
1. IMyclass must be interface 1.IMyclass必须是接口
2. The dynamic type of IMyclass known only at init (i have no constructor after:) ) 2. IMyclass 的动态类型仅在 init 时才知道(之后我没有构造函数:))
3. I could do it using a reflection or definition method clone at IMyclass is there any better solutions? 3. 我可以在 IMyclass 使用反射或定义方法克隆来做到这一点,有没有更好的解决方案?

Thank you.谢谢你。

You could pass a provider into class A您可以将提供程序传递给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.请注意,如果InitCreateMyClass之前没有被调用,这两个示例都会崩溃,您需要进行一些检查,或者更好的是在构造函数中执行您的 init。

Have I understood the question correctly?我是否正确理解了这个问题?

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.基本上,您有一个 class A在初始化时填充有工厂(或提供者)。 Then you use A instead of calling new .然后你使用A而不是调用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)编辑:添加register(Class, Class)

If you just want to instantiate the same class in CreateMyClass() without further configuration you can use reflection.如果您只想在CreateMyClass()中实例化相同的 class 而无需进一步配置,则可以使用反射。

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.您可能正在寻找BuilderFactory模式。

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() .您可以将getInstance()方法放在隐藏接口上(位于与IMyClassMyClassImplA相同的 package 中,但不是ClientOfA ),然后将MyClassImpl的原型传递给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).这个解决方案需要反射来创建MyClassImpl的原型实例,这可以通过 Spring (或其他形式的依赖注入)来完成。 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.作为记录,我什至会考虑提倡这种解决方案的唯一原因是因为它会预先进行一次反射,而不是每次调用createMyClass()时,原始发布者表示他/她会经常这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM