创建型模式之抽象工厂模式

工厂三兄弟:简单工厂模式,工厂方法模式,抽象工厂模式我选最优讲解,以后其他的设计模式都选用改良版最优模式讲解,其他的请自行百度。

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是我们本文将要学习的抽象工厂模式的基本思想。
 
界面皮肤库的初始设计(案例)
Sunny软件公司欲开发一套界面皮肤库,可以对Java桌面软件进行界面美化。为了保护版权,该皮肤库源代码不打算公开,而只向用户提供已打包为jar文件的class字节码文件。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,其结构示意图如图所示:
 

完整解决方案:

Sunny公司开发人员使用抽象工厂模式来重构界面皮肤库的设计,其基本结构如图所示:

 

界面皮肤库结构图:

在图中,SkinFactory接口充当抽象工厂,其子类SpringSkinFactory和SummerSkinFactory充当具体工厂,接口Button、TextField和ComboBox充当抽象产品,其子类SpringButton、SpringTextField、SpringComboBox和SummerButton、SummerTextField、SummerComboBox充当具体产品。完整代码如下所示:

按钮:

//在本实例中我们对代码进行了大量简化,实际使用时,界面组件的初始化代码较为复杂
//按钮接口:抽象产品
interface Button {
    public void display();
}
//Spring按钮类:具体产品
class SpringButton implements Button {
     public void display() { 
          System.out.println("显示浅绿色按钮。");
     }
}
//Summer按钮类:具体产品
class SummerButton implements Button {
     public void display() { 
          System.out.println("显示浅蓝色按钮。");
     }
}    

 

文本框:

//文本框接口:抽象产品
interface TextField {
    public void display();
}
//Spring文本框类:具体产品
class SpringTextField implements TextField {
    public void display() { 
        System.out.println("显示绿色边框文本框。");
    }
}
//Summer文本框类:具体产品
class SummerTextField implements TextField {
    public void display() { 
          System.out.println("显示蓝色边框文本框。");
     }
}

 

组合框:

//组合框接口:抽象产品
interface ComboBox {
    public void display();
}
//Spring组合框类:具体产品
class SpringComboBox implements ComboBox {
    public void display() { 
         System.out.println("显示绿色边框组合框。");
    }
}
//Summer组合框类:具体产品
class SummerComboBox implements ComboBox {
    public void display() { 
         System.out.println("显示蓝色边框组合框。");
    }
}

 

开始创建界面皮肤工厂:

//界面皮肤工厂接口:抽象工厂
interface SkinFactory {
    public Button createButton();
    public TextField createTextField();
    public ComboBox createComboBox();
}
//Spring皮肤工厂:具体工厂
class SpringSkinFactory implements SkinFactory { 
     public Button createButton() {
         return new SpringButton();
     }

     public TextField createTextField() { 
         return new SpringTextField();
     }

     public ComboBox createComboBox() { 
         return new SpringComboBox();
     }
}
//Summer皮肤工厂:具体工厂
class SummerSkinFactory implements SkinFactory {
     public Button createButton() { 
         return new SummerButton();
     }

     public TextField createTextField() { 
         return new SummerTextField();
     }

     public ComboBox createComboBox() { 
         return new SummerComboBox();
     }
}

 

为了让系统具备良好的灵活性和可扩展性,我们引入了工具类XMLUtil和配置文件,

XMLUtil类的代码如下所示:

import javax.xml.parsers.*; 
import org.w3c.dom.*;
import org.xml.sax.SAXException; 
import java.io.*;

public class XMLUtil {
        //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
        public static Object getBean() {
            try {
                //创建文档对象
                DocumentBuilderFactory dFactory = DocumentBuilderFactory
                DocumentBuilder builder = dFactory.newDocumentBuilder();
                Document doc;
                doc = builder.parse(new File("config.xml"));
                //获取包含类名的文本节点
                NodeList nl = doc.getElementsByTagName("className");
                Node classNode = nl.item(0).getFirstChild();
                String cName = classNode.getNodeValue();
                //通过类名生成实例对象并将其返回
                Class c = Class.forName(cName);
                Object obj = c.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
      }
}

配置文件config.xml中存储了具体工厂类的类名,代码如下所示:

<?xml version="1.0"?>
<config>
    <className>SpringSkinFactory</className>
</config>

编写如下客户端测试代码:

class Client {
     public static void main(String args[]) {
           //使用抽象层定义SkinFactory factory;
           Button bt; TextField tf; ComboBox cb;
           factory = (SkinFactory)XMLUtil.getBean(); 
           bt = factory.createButton();
           tf = factory.createTextField(); 
           cb = factory.createComboBox(); 
       bt.display(); tf.display(); cb.display(); } }

编译并运行程序,输出结果如下:

显示浅绿色按钮。
显示绿色边框文本框。
显示绿色边框组合框。

如果需要更换皮肤,只需修改配置文件即可,在实际环境中,我们可以提供可视化界面,例如菜单或者窗口来修改配置文件,用户无须直接修改配置文件。如果需要增加新的皮肤,只需增加一族新的具体组件并对应提供一个新的具体工厂,修改配置文件即可使用新的皮肤, 原有代码无须修改,符合“开闭原则”。

 

 

posted @ 2020-10-12 11:09  47号Gamer丶  阅读(136)  评论(0编辑  收藏  举报