首先,放上項目github地址: https://github.com/codethereforam/java-design-patterns, 我是用java實現的html
題目中的這三個設計模式屬於建立型模式
,做用是爲了抽象實例化過程。java
我以前學過這三個設計模式,但最近發現又沒法釐清這三個的區別了,爲了不下次又忘了,因而想動手記錄下來。mysql
可能有同窗有疑問,提早說一下,下面所展現的類圖
由IDEA
自帶插件UML Support
自動生成,而時序圖
由插件SequencePlugin
自動生成。若是有同窗對類圖和時序圖還不瞭解,請先google自學一下。git
下面我結合模擬場景總結一下這三個模式,具體代碼請點擊本文開頭的github連接。github
模擬場景:一個用戶管理系統,假設只有一張User表。原本用的mysql,但需求忽然發生變化,如今要用Oralce,因爲這兩個數據庫的SQL語句有些差異,須要重寫數據庫層面的代碼,如今要求系統能夠靈活切換數據庫。sql
關鍵代碼:數據庫
public class UserDAOFactory { //靜態工廠方法 public static UserDAO createUserDAO(String database) { UserDAO userDAO = null; switch (database) { case "mysql": userDAO = new UserDAOMysqlImpl(); break; case "oracle": userDAO = new UserDAOOracleImpl(); break; default: } return userDAO; } }
分析:若是如今要改用SQL server
數據庫,須要添加一個UserDAOSqlserverImpl
,而後在UserDAOFactory
類的createUserDAO
方法中添加一個case,這顯然違背了開閉原則
。設計模式
模擬場景:和上述簡單工廠模擬場景同樣oracle
分析:若是如今要改用SQL server
數據庫,則需添加一個UserDAOSqlserverImpl
和相應的工廠UserDAOFactorySqlserverImpl
,再更改Main中的實例化代碼,這知足了開閉原則
,擴展很方便。但若是支持的數據庫一多,那工廠就會氾濫。google
模擬場景:在以前的場景基礎上,若是系統原本還有一個日誌表,是用來記錄日誌的。
分析:若是如今要改用SQL server
數據庫,則需添加UserDAOSqlserverImpl
、LogDAOSqlserverImpl
和DAOFactorySqlserverImpl
,再更改Main中的實例化代碼。但若是如今要添加一個其餘的表,那麼就要改DAOFactory
接口和接口中方法的實現,要改動的地方太多。
關鍵代碼(選取DataAccess
):
public UserDAO createUserDAO() { UserDAO userDAO = null; switch (database) { case MYSQL: userDAO = new UserDAOMysqlImpl(); break; case ORACLE: userDAO = new UserDAOOracleImpl(); break; default: } return userDAO; }
分析:與抽象工廠相比,該方法減小了三個類,添加了一個DataAccess
類,類的數量減小了,系統複雜性下降。若是如今要改用SQL server
數據庫,則需添加UserDAOSqlserverImpl
和LogDAOSqlserverImpl
,而後在DataAccess
類中的createUserDAO
方法和createLogDAO
方法分別添加一個case,這違背了開閉原則。
關鍵代碼(選取DataAccess
):
public static final String PACKAGE_NAME = DataAccess.class.getPackage().getName(); public UserDAO createUserDAO() throws ClassNotFoundException, IllegalAccessException, InstantiationException { String className = PACKAGE_NAME + ".UserDAO" + database + "Impl"; return (UserDAO) Class.forName(className).newInstance(); }
分析:若是要換數據庫,則無需修改DataAccess
類中的代碼。若是要添加表,只須要添加一個抽象產品接口和兩個具體產品實現,而後在DataAccess
中添加一個create**
方法,擴展起來很是方便。
若是你仔細看到這,你可能會以爲我例子舉的不恰當,哪裏有系統只有一個表的呢,前面的場景直接考慮抽象工廠就好了。我認可我舉的例子有問題,以前寫代碼時沒有發現,應該是當時理解的還不夠深刻。
簡單工廠和工廠方法的模擬場景應該改成:系統原本有一直表,但如今要添加表,而不是換數據庫。而抽象工廠的模擬場景應該改成:在上述的基礎上要換數據庫。若是你理解了三個模式,我想這兩個模擬場景你應該也知道怎麼實現了。
本文的例子我參考了大話設計模式
,但其餘代碼和文字是我本身的理解。若是有錯誤,望各位不吝賜教,在評論區指出。