Abstract Factory in Java - How to extend?
I use java library, core
, with AbstractFactory
responsible for UI components. MyApplication uses core and customizes the UI. Therefore during startup of MyApplication I set MyFactory as an instance of AbstractFactory.
class AbstractFactory {
...
public static AbstractFactory getInstance();
public abstract JButon createButton();
public abstract JLabel createLabel();
...
}
class MyFactory extends AbstractFactory {
...
}
MyApplication.startup() {
AbstractFactory.setInstance(new MyFactory())
}
My problem is, that I need to create, for example, JList in MyApplication, but I cannot add public JList createJList()
in AbstractFactory, because I cannot modify core library.
What shall I do?
Case One:
Always call MyFactory.getMyFactoryInstance()
in MyApplication, new static field.
class MyFactory extends AbstractFactory {
private static MyFactory myInstance = new MyFactory();
public static getMyFactoryInstance() { return myInstance }
...
}
Case Two:
Al开发者_如何学Pythonways call MyFactory.getMyFactoryInstance()
in MyApplication, use cast
class MyFactory extends AbstractFactory {
public static MyFactory getMyFactoryInstance() {
if (getInstance() instanceOf MyFactory) {
return (MyFactory) getInstance();
}
throw Exception();
}
...
}
Case Three: Use Two Factories. For JButtons and JLabels, use AbstractFactory, for JList use SomeOtherFactory.
JButton button = AbstractFactory.getInstance().createButton();
JList list = SomeOtherFactory.getInstance.createList();
Case Four: Something better? I feel I overlooked something.
I would create an abstract subclass of AbstractFactory
that specifies the createJList()
method and overwrites the getInstance()
method which returns the new abstract class type. You can then implement the logic within your MyFactory class and keep to the principle of programming to interfaces (in this case, abstractions), not implementations!
Example code:
public abstract class MyAbstractFactory extends AbstractFactory {
//you could implement AbstractFactory's abstract methods here
public abstract JList createJList();
}
public class MyFactory extends MyAbstractFactory {
private static MyAbstractFactory instance;
private MyFactory() {}
public JList createJList() {
//implementation of method here
}
public static MyAbstractFactory getInstance() {
if (instance == null) instance = new MyFactory();
return instance;
}
}
The above example uses lazy instantiation, which is great if the code isn't always used and is not used in a multi threaded application. If it is however used in a multi-threaded way I would use the following implementation of MyFactory
that uses double-checked locking to deal with multiple threads.
public class MyFactory extends MyAbstractFactory {
private volatile static MyAbstractFactory instance;
private MyFactory() {}
public JList createJList() {
//implementation of method here
}
public static MyAbstractFactory getInstance() {
if (instance == null) {
syncronized(MyFactory.class) {
if (instance == null) instance = new MyFactory();
}
}
return instance;
}
}
With either implementation the usage will remain the same.
Usage:
MyAbstractFactory factory = MyFactory.getInstance();
factory.createJList();
Since you need different factories to build different things, have you considered incorporating generics?
interface Factory<T> {
...
T create();
...
}
Just have a typed factory for every type of thing you need to create. For example:
class JButtonFactory implements Factory<JButton> {
public JButton create() {
return new JButton();
}
}
精彩评论