|
假如你要制作一个对话框控件,你希望这个对话框可以有不同的Look&Feel,最基本的想法是,使用setter将不同的Look&Feel注入到这个对话框,例如:
CustomDialog.java
Java代码
1.public class CustomDialog {
2. private IButton button;
3. private ITextField textField;
4.
5. public void setButton(IButton button) {
6. this.button = button;
7. }
8.
9. public void setTextField(ITextField textField) {
10. this.textField = textField;
11. }
12.
13. public void layoutAllComponents() {
14. // ....
15. }
16.
17. public void showDialog() {
18. this.paintDialog();
19. button.paintButton();
20. textField.paintTextField();
21. }
22.
23. public void paintDialog() {
24. System.out.println("custom dialog paints....");
25. }
26.}
很简单,这是最基本的界面依赖,setter依赖于IButton和ITextField两个界面,而不是其实作类别,不过这里还有一个进一步的 要求,使用上面的方式还必须亲自调用setter、layout等方法。如果你希望皮肤的更换可以更加简单些,例如只需要透过一个元件的替换就可以完成对 话框所有元件的观感更换。
你可以使用Abstract Factory模式,将所有的对话框需要产生的元件加以封装,对话框依赖于Abstract Factory,实际上具体的Factory的实现则分别产生对话框所需要的控件,下面的UML类图将展示这种概念。
现在如果要更换所有的控件,只需要注入具体的Factory就可以了,例如:
Java代码
1.CustomDialog windowsDialog =
2. new CustomDialog(new WindowsWidgetFactory());
3.windowsDialog.showDialog();
4.
5.CustomDialog macDialog =
6. new CustomDialog(new MacWidgetFactory());
7.macDialog.showDialog();
将上面的UML图实现出来:
CustomDialog.java
Java代码
1.public class CustomDialog {
2. private IButton button;
3. private ITextField textField;
4.
5. public CustomDialog(IWidgetFactory widgetFactory) {
6. setWidgetFactory(widgetFactory);
7. }
8.
9. // 由于客户端只依赖于抽象工厂,工厂如何运作跟客户端无关。
10. // 要抽换工厂并不需要改动客户端程序
11. public void setWidgetFactory(IWidgetFactory widgetFactory) {
12. setButton(widgetFactory.createButton());
13. setTextField(widgetFactory.createTextField());
14. // ....
15. }
16.
17. public void layoutAllComponents() {
18. // layout all components
19. }
20.
21. // 这里也是依赖抽象,实际改变控件实例
22. // 客户端代码也不需要修改
23. public void setButton(IButton button) {
24. this.button = button;
25. }
26.
27. public void setTextField(ITextField textField) {
28. this.textField = textField;
29. }
30.
31. public void showDialog() {
32. this.paintDialog();
33. button.paintButton();
34. textField.paintTextField();
35. }
36.
37. public void paintDialog() {
38. System.out.println("custom dialog paints....");
39. }
40.}
IButton.java
Java代码
1.public interface IButton {
2. public void paintButton();
3.}
ITextField.java
Java代码
1.public interface ITextField {
2. public void paintTextField();
3.}
IWidgetFactory.java
Java代码
1.public interface IWidgetFactory {
2. public IButton createButton();
3. public ITextField createTextField();
4.}
MacButton.java
Java代码
1.public class MacButton implements IButton {
2. public void paintButton() {
3. System.out.println("Mac button paints....");
4. }
5.}
WindowsButton.java
Java代码
1.public class WindowsButton implements IButton {
2. public void paintButton() {
3. System.out.println("Windows button paints....");
4. }
5.}
MacTextField.java
Java代码
1.public class MacTextField implements ITextField {
2. public void paintTextField() {
3. System.out.println("Mac textField paints....");
4. }
5.}
WindowsTextField.java
Java代码
1.public class WindowsTextField implements ITextField {
2. public void paintTextField() {
3. System.out.println("Windows textField paints....");
4. }
5.}
MacWidgetFactory.java
Java代码
1.public class MacWidgetFactory implements IWidgetFactory {
2. public IButton createButton() {
3. return new MacButton();
4. }
5.
6. public ITextField createTextField() {
7. return new MacTextField();
8. }
9.}
WindowsWidgetFactory.java
Java代码
1.public class WindowsWidgetFactory
2. implements IWidgetFactory {
3. public IButton createButton() {
4. return new WindowsButton();
5. }
6.
7. public ITextField createTextField() {
8. return new WindowsTextField();
9. }
10.}
下图是Abstract Factory模式的UML结构图:
简单的说,在Abstract Factory模式中将具体的Product封装在Factory实现中,而库户仍只要面对Factory与Product的抽象界面,避免依赖于具体的 Factory与Product,由于Factory封装了所有必须的Product,所以要更换所有的控件,只需要简单地替换掉Factory的具体实 现就可以了,不需要修改客户端的程序。
事例2:
The intent of Abstract Factory is to provide for the creation of a family of related, or dependent, objects. see pic:
Additional note is below:( reference from http://www.dofactory.com) :
•AbstractFactory (ContinentFactory)
odeclares an interface for operations that create abstract products
•ConcreteFactory (AfricaFactory, AmericaFactory)
oimplements the operations to create concrete product objects
•AbstractProduct (Herbivore, Carnivore)
odeclares an interface for a type of product object
•Product (Wildebeest, Lion, Bison, Wolf)
odefines a product object to be created by the corresponding concrete factory
oimplements the AbstractProduct interface
•Client (AnimalWorld)
ouses interfaces declared by AbstractFactory and AbstractProduct classes
using the term: 产品族(Product Family),the former pic is like:
In this pattern, speaking loosely, a package is usually a "family" of classes, and an abstract factory produces a "family" of objects.
• /* GUIFactory example --
• The output should be either "I'm a WinButton" or "I'm an OSXButton"
• depending on which kind of factory was used. Note that the Application
• has no idea what kind of GUIFactory it is given or even what kind of
• Button that factory creates.*/
•
• interface GUIFactory {
• public Button createButton();
• }
•
•
• class WinFactory implements GUIFactory {
• public Button createButton() {
• return new WinButton();
• }
• }
•
•
• class OSXFactory implements GUIFactory {
• public Button createButton() {
• return new OSXButton();
• }
• }
•
•
•
• interface Button {
• public void paint();
• }
•
•
• class WinButton implements Button {
• public void paint() {
• System.out.println("I'm a WinButton");
• }
• }
•
•
• class OSXButton implements Button {
• public void paint() {
• System.out.println("I'm an OSXButton");
• }
• }
•
•
• class Application {
• public Application(GUIFactory factory){
• Button button = factory.createButton();
• button.paint();
• }
• }
•
• public class ApplicationRunner {
• public static void main(String[] args) {
• new Application(createOsSpecificFactory());
• }
•
• public static GUIFactory createOsSpecificFactory() {
• int sys = readFromConfigFile("OS_TYPE");
• if (sys == 0) {
• return new WinFactory();
• } else {
• return new OSXFactory();
• }
• }
• } |
|