2011-05-27 37 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