工廠模式分為簡單工廠、工廠方法模式和抽象工廠模式。簡單工廠顧名思義是最簡單的,從一個(gè)工廠獲取所需的產(chǎn)品類似于factory.getPRoduct1();或factory.getProduct2(),最經(jīng)典的運(yùn)用switch語句。簡單工廠要增加產(chǎn)品要修改源碼,破壞ocp原則(對擴(kuò)展開放,修改封閉)
工廠方法模式與簡單工廠最不一樣的是工廠方法模式有工廠接口
抽象工廠模式與工廠方法模式最大的不同:工廠方法模式的產(chǎn)品都衍生于同一個(gè)接口或抽象類,而抽象工廠模式的產(chǎn)品衍生自不同的接口或抽象類。因?yàn)楣S方法模式針對一個(gè)產(chǎn)品等級結(jié)構(gòu),而抽象工廠方法針對多個(gè),分別對應(yīng)一個(gè)接口(抽象類)和多個(gè)接口(抽象類)。什么產(chǎn)品等級結(jié)構(gòu)?舉個(gè)例子,比如車子,分奧迪和寶馬,而奧迪和寶馬分為大排量和小排量的,那么大排量的奧迪和小排量的奧迪屬于同一產(chǎn)品等級結(jié)構(gòu),而大排量的奧迪和大排量的寶馬屬于同一產(chǎn)品族。如果針對一個(gè)產(chǎn)品等級結(jié)構(gòu),也就是奧迪或?qū)汃R,那么工廠產(chǎn)品為一個(gè)產(chǎn)品等級結(jié)構(gòu)就使用工廠方法模式,如果針對多個(gè),如寶馬和奧迪,那么就使用抽象工廠模式,它的產(chǎn)品是一個(gè)產(chǎn)品族。這就是它們的應(yīng)用場景。
這里用一個(gè)例子熟悉一下抽象工廠模式。(使用單例模式避免大量工廠創(chuàng)建,浪費(fèi)資源,不懂看前面有一篇說單例的)
public interface IFactoryDao { public IUserDao createUserDao(); public IAddressDao createAddressDao();}//工廠接口public interface IAddressDao { public void add(Address address,int userId); public void update(Address address); public void delete(int id); }//產(chǎn)品1接口public interface IUserDao { public void add(User user); public void delete(int id); public void update(User user); }//產(chǎn)品2接口public class UserJDBCDao implements IUserDao { @Override public void add(User user) { System.out.println("UserJDBCDao....add"); } @Override public void delete(int id) { System.out.println("UserJDBCDao....delete"); } @Override public void update(User user) { System.out.println("UserJDBCDao....update"); }}//針對JDBC的產(chǎn)品2實(shí)現(xiàn)public class AddressJDBCDao implements IAddressDao { @Override public void add(Address address, int userId) { System.out.println("addressJDBCDao....add"); } @Override public void update(Address address) { System.out.println("addressJDBCDao....update"); } @Override public void delete(int id) { System.out.println("addressJDBCDao....delete"); } }//針對JDBC的產(chǎn)品1實(shí)現(xiàn)public class JDBCDaoFactory implements IFactoryDao { private static JDBCDaoFactory factory = new JDBCDaoFactory(); private JDBCDaoFactory(){} public static IFactoryDao getInstance() { return factory; } @Override public IUserDao createUserDao() { return new UserJDBCDao(); } @Override public IAddressDao createAddressDao() { return new AddressJDBCDao(); }}//工廠接口實(shí)現(xiàn)1(JDBC)public class UserMySQLDao implements IUserDao { @Override public void add(User user) { System.out.println("UserMySqlDao....add"); } @Override public void delete(int id) { System.out.println("UserMySQlDao....delete"); } @Override public void update(User user) { System.out.println("UserMySqlDao....update"); } }//針對MySql的產(chǎn)品2實(shí)現(xiàn)public class AddressMySqlDao implements IAddressDao { @Override public void add(Address address, int userId) { System.out.println("addressMySqlDao....add"); } @Override public void update(Address address) { System.out.println("addressMySqlDao...update"); } @Override public void delete(int id) { System.out.println("addressMySqlDao....delete"); } }//針對MySql的產(chǎn)品1實(shí)現(xiàn)public class MysqlDaoFactory implements IFactoryDao { private static IFactoryDao factory = new MysqlDaoFactory(); private MysqlDaoFactory() { } public static IFactoryDao getInstance() { return factory; } @Override public IAddressDao createAddressDao() { return new AddressMySqlDao(); } @Override public IUserDao createUserDao() { return new UserMySqlDao(); } }//工廠實(shí)現(xiàn)2(MySql)由兩個(gè)工廠可以發(fā)現(xiàn),兩個(gè)工廠里的產(chǎn)品都是產(chǎn)品族(AddressMySqlDao和AddressJDBCDao是同一個(gè)接口的實(shí)現(xiàn))--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在項(xiàng)目中調(diào)用工廠1或2也要修改代碼,這也不好,因此可以用反射。把要?jiǎng)?chuàng)建的工廠className寫在配置文件這樣只需修改配置文件即可,靈活、不破壞封裝性、ocp。
package com.yan.factory.dao;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;public class DaoUtil { public static IFactoryDao createDaoFactory() { IFactoryDao f = null; try { Properties prop = PropertiesUtil.getDaoProp(); String fs = prop.getProperty("factory"); Class clz = Class.forName(fs); String mn = "getInstance"; Method m = clz.getMethod(mn); f = (IFactoryDao)m.invoke(clz); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalaccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return f; }}dao.properties文件
factory=com.yan.factory.dao.JDBCDaoFactory可修改配置文件測試。在項(xiàng)目中private IAddressDao addressDao = DaoUtil.createDaoFactory().createAddressDao();即可
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面有點(diǎn)缺點(diǎn)就是太繁雜,要?jiǎng)?chuàng)建多個(gè)工廠實(shí)例,我們可以利用反射,只創(chuàng)建一個(gè)工廠,把要?jiǎng)?chuàng)建的Dao寫在配置文件
package com.yan.factory.dao;import java.util.HashMap;import java.util.Map;import java.util.Properties;public class PropertiesFactory implements IFactoryDao { private static PropertiesFactory f = new PropertiesFactory(); private PropertiesFactory() { } public static IFactoryDao getInstance() { return f; } @Override public Object getDao(String name) { try { Properties prop = PropertiesUtil.getDaoProp(); String cn = prop.getProperty(name); Object obj = Class.forName(cn).newInstance(); System.out.println(obj); return obj; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; }}factory=com.yan.factory.dao.PropertiesFactoryUserDao="com.yan.factory.dao.UserJDBCDao"
新聞熱點(diǎn)
疑難解答