首先,放上项目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**
方法,扩展起来很是方便。
若是你仔细看到这,你可能会以为我例子举的不恰当,哪里有系统只有一个表的呢,前面的场景直接考虑抽象工厂就好了。我认可我举的例子有问题,以前写代码时没有发现,应该是当时理解的还不够深刻。
简单工厂和工厂方法的模拟场景应该改成:系统原本有一直表,但如今要添加表,而不是换数据库。而抽象工厂的模拟场景应该改成:在上述的基础上要换数据库。若是你理解了三个模式,我想这两个模拟场景你应该也知道怎么实现了。
本文的例子我参考了大话设计模式
,但其余代码和文字是我本身的理解。若是有错误,望各位不吝赐教,在评论区指出。