工厂方法有两个缺点,一是如果要增加一个产品的话,虽然原来的已有代码不需要改动,但是要成对地增加类。一个产品对应一个工厂。再者就是如果有些产品是要在一起出现的话,管理起来容易出错。比如说界面UI。打个比方,假如每套UI包含两个样式,一个是标题样式,一个是正文样式。如果有两套UI,那么就有4个具体工厂和4个具体产品,如果想要更换UI,就得获取对应的两个产品(标题样式和正文样式)。如果需求改动,要增加更多的UI,那么工厂方法模式或许不是一种好方法。

抽象工厂模式弥补了工厂方法模式的这两个缺点。抽象工厂模式里面一个抽象工厂生产多个产品。比如说一个网站,站长开发了多套UI供用户使用。用户用多套UI里面选择自己喜欢的UI。每套UI都包括标题样式和正文样式。那么UI抽象工厂里面有两个抽象的工厂方法,一个方法生产一种产品。

以下的例子基于一个产业只生产两种产品,手机和电视。有两个厂商,HuaWeiZTE

目录结构如下:

| | |-Client.java
| | |-Factory.java
| | |-factory.properties
| | |-HuaWeiFactory.java
| | |-HuaWeiPhone.java
| | |-HuaWeiTV.java
| | |-Phone.java
| | |-PropertyUtil.java
| | |-TV.java
| | |-ZTEFactory.java
| | |-ZTEPhone.java
| | `-ZTETV.java

Factory.java抽像工厂类

public interface Factory{
    Phone createPhone();//工厂方法,生产手机
    TV createTV();//工厂方法,生产电视
}

HuaWei具体工厂类HuaWeiFactory.java

public class HuaWeiFactory implements Factory{
    public Phone createPhone(){
        HuaWeiPhone phone = new HuaWeiPhone();
        return phone;
    }

    public TV createTV(){
        HuaWeiTV tv = new HuaWeiTV();
        return tv;
    }
}

手机抽象类Phone.java

public interface Phone{
    public void display();
}

HuaWei手机具体类HuaWeiPhone.java

public class HuaWeiPhone implements Phone{
    public void display(){
        System.out.println("HuaWeiPhone");
    }
}

电视抽象类TV.java

public interface TV{
    public void display();
}

HuaWei电视具体类HuaWeiTV.java

public class HuaWeiTV implements TV{
    public void display(){
        System.out.println("HuaWeiTV");
    }
}

工厂配置文件factory.properties

className=HuaWeiFactory

配置文件工具类PropertyUtil.java

import java.io.*;
import java.util.*;
public class PropertyUtil{
    public static Object getBean(){
        Object obj = null;
        try{
            Properties prop = new Properties();
            InputStream in = new BufferedInputStream(new FileInputStream("factory.properties"));
            prop.load(in);
            String className = prop.getProperty("className");
            Class c = Class.forName(className);
            obj = c.newInstance();
        }catch(Exception e){
            //Exception
            e.printStackTrace();
        }
        return obj;
    }
}

客户端代码Client.java

public class Client{
    public static void main(String args[]){
        Factory factory = (Factory)PropertyUtil.getBean();
        Phone phone = factory.createPhone();
        TV tv = factory.createTV();
        phone.display();
        tv.display();
    }
}

抽像工厂模式如果要增加厂商的话,那就很方便。但是如果要增加某一种产品的话,就得修加已有和各个类中的代码。抽象工厂模式比较适合那种固定产品类型的场景。

上面的例子中,如果要增加一个厂商ZTE的话很方便。

ZTE手机具体产品类ZTEPhone.java

public class ZTEPhone implements Phone{
    public void display(){
        System.out.println("ZTEPhone");
    }
}

ZTE电视具体产品类ZTETV.java

public class ZTETV implements TV{
    public void display(){
        System.out.println("ZTETV");
    }
}

ZTE具体工厂类ZTEFactory.java

public class ZTEFactory implements Factory{
    public Phone createPhone(){
        ZTEPhone phone = new ZTEPhone();
        return phone;
    }
    public TV createTV(){
        ZTETV tv = new ZTETV();
        return tv;
    }
}

(完)