定義: 定義: 提供一個創建一系列相關或相互依賴對象的介面,而無需指定他們具體的類。 結構:(書中圖,侵刪) 這個圖相對來說有一點點複雜,其實就是在工廠方法模式的基礎上做了一些擴展,工廠方法模式只用於生成一種產品(把上圖ProductB相關的都去掉就是了),而抽象工廠模式可用於生產多種產品。 加上例 ...
定義:
提供一個創建一系列相關或相互依賴對象的介面,而無需指定他們具體的類。結構:(書中圖,侵刪)

實例:
鑒於書中的例子相當的常見,所以決定延用書中的例子。 就是更換資料庫的例子。 假設系統中有員工、部門兩個類。 然後系統需要使用mysql和oracle兩個資料庫。 為了代碼簡潔,不分什麼dao層之類的,直接把調用資料庫的方法寫在實體里。 員工抽象類:package designpattern.abstractfactory; public abstract class Employee { private String name; abstract void insert(Employee employee); public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Employee [name=" + name + "]"; } }oracle員工類:
package designpattern.abstractfactory; public class OracleEmployee extends Employee { @Override void insert(Employee employee) { System.out.println("往oracle資料庫插入一條Employee員工數據:" + employee); } }mysql員工類:
package designpattern.abstractfactory; public class MysqlEmployee extends Employee { @Override public void insert(Employee employee) { System.out.println("往mysql資料庫插入一條Employee員工數據:" + employee); } }部門抽象類:
package designpattern.abstractfactory; public abstract class Department { String name; abstract void insert(Department department); public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Department [name=" + name + "]"; } }oracle部門類:
package designpattern.abstractfactory; public class OracleDepartment extends Department { @Override void insert(Department department) { System.out.println("往oracle資料庫插入一條Department部門數據:" + department); } }mysql部門類:
package designpattern.abstractfactory; public class MysqlDepartment extends Department { @Override void insert(Department department) { System.out.println("往mysql資料庫插入一條Department部門數據:"+department); } }抽象工廠類:
package designpattern.abstractfactory; public interface Factory { Employee createEmployee(); Department createDepartment(); }mysql工廠類:
package designpattern.abstractfactory; public class MysqlFactory implements Factory { @Override public Employee createEmployee() { return new MysqlEmployee(); } @Override public Department createDepartment() { return new MysqlDepartment(); } }oracle工廠類:
package designpattern.abstractfactory; public class OracleFactory implements Factory { @Override public Employee createEmployee() { return new OracleEmployee(); } @Override public Department createDepartment() { return new OracleDepartment(); } }客戶端:
package designpattern.abstractfactory; public class Client { public static void main(String[] args) { Factory factory = new MysqlFactory(); // Factory factory=new OracleFactory(); Employee employee = factory.createEmployee(); employee.setName("張三"); employee.insert(employee); Department department = factory.createDepartment(); department.setName("技術部"); department.insert(department); } }結果輸出:
往mysql資料庫插入一條Employee員工數據:Employee [name=張三]
往mysql資料庫插入一條Department部門數據:Department [name=技術部]
這個設計模式很好的解除了客戶端與實例創建過程的耦合,通過抽象出介面的方式,使客戶端只需要和介面打交道。 同時也使得切換資料庫變得容易,只需要修改初始化的語句即可。 這同樣也是這個模式的不足之處,意味著所有需要用到資料庫連接的地方都要寫上這句初始化語句,使得修改的工作量變得很大。 接下來就一步一步優化它: 首先,使用哪個資料庫的判斷是在客戶端,我們需要把這個判斷轉移,使用簡單工廠模式,將判斷轉移至簡單工廠: 簡單工廠:
package designpattern.abstractfactory; public class SimpleFactory { static String db = "mysql"; //static String db="oracle"; static Employee createEmployee() { switch (db) { case "mysql": return new MysqlEmployee(); case "oracle": return new OracleEmployee(); default: return null; } } static Department createDepartment() { switch (db) { case "mysql": return new MysqlDepartment(); case "oracle": return new OracleDepartment(); default: return null; } } }客戶端:
package designpattern.abstractfactory; public class Client2 { public static void main(String[] args) { Employee employee = SimpleFactory.createEmployee(); employee.setName("張三"); employee.insert(employee); Department department = SimpleFactory.createDepartment(); department.setName("技術部"); department.insert(department); } }
然後,如果再增加一個資料庫,需要在所有的方法里增加switch的case,這也是很麻煩的事情,這裡需要用到反射來解決這個問題: 反射版簡單工廠:
package designpattern.abstractfactory; public class ReflectSimpleFactory { static String db = "Mysql"; // static String db="Oracle"; static String path = "designpattern.abstractfactory";// 包路徑 static Employee createEmployee() { try { Class<Employee> employee = (Class<Employee>) Class.forName(path + "." + db + "Employee"); return employee.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } static Department createDepartment() { try { Class<Department> department = (Class<Department>) Class.forName(path + "." + db + "Department"); return department.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }客戶端:
package designpattern.abstractfactory; public class Client3 { public static void main(String[] args) { Employee employee = ReflectSimpleFactory.createEmployee(); employee.setName("張三"); employee.insert(employee); Department department = ReflectSimpleFactory.createDepartment(); department.setName("技術部"); department.insert(department); } }通過反射,將程式由編譯時改為運行時,徹底取代了switch語句。 現在,還剩最後一個問題,決定使用什麼資料庫的字元串還是寫在代碼中,修改之後還需要重新編譯,這裡只需要把字元串改到配置文件中即可: 簡單工廠:
package designpattern.abstractfactory; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class ReflectSimpleFactory2 { static String path = "designpattern.abstractfactory";// 包路徑 static Employee createEmployee() { try { Class<Employee> employee = (Class<Employee>) Class.forName(path + "." + getDBName() + "Employee"); return employee.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } static Department createDepartment() { try { Class<Department> department = (Class<Department>) Class.forName(path + "." + getDBName() + "Department"); return department.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } private static String getDBName() { String dbName = null; try { InputStream in = ReflectSimpleFactory2.class.getResourceAsStream("db.properties"); Properties pro = new Properties(); pro.load(in); in.close(); dbName = pro.getProperty("db"); } catch (IOException e) { e.printStackTrace(); } return dbName; } }配置文件:
db=Mysql
#db=Oracle
客戶端:
package designpattern.abstractfactory; public class Client4 { public static void main(String[] args) { Employee employee = ReflectSimpleFactory2.createEmployee(); employee.setName("張三"); employee.insert(employee); Department department = ReflectSimpleFactory2.createDepartment(); department.setName("技術部"); department.insert(department); } }大功告成!