被说了很多遍的设计模式---抽象工厂模式
2016-11-03 21:16
435 查看
[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍抽象工厂模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:
操作系统:win7
x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------
在产品簇的范围内选择合适对象的问题,如数据库驱动。(产品簇:相同功能的不同实例)
要点一:所有产品具有相似的功能或属性。
要点二:所有产品在实现上存在差异。
创建SqlDB.java文件,具体内容如下:(在此为简化实现过程,实际代码仅作为示例,简单的SQL连接代码,见注释部分)
在前文中,我们介绍了工厂方法模式,在此,我们先来看看使用工厂方法模式的实现过程。
创建IFactory.java文件,具体内容如下:
优点:切换数据时,仅需修改IFactory f = new SqlserverFactory();及对应的SQL语句。
缺点:任何新增和修改,都可能会导致需要针对不同的数据库进行对应的实现。
推荐写法:(抽象工厂模式)
详细代码与上文类似,工程结构图见下文模式总结部分。
创建DateAccess.java文件,具体内容如下:
创建Window.java文件,具体内容如下:
创建Init.java文件,具体内容如下:
标准抽象工厂模式UML结构图:
组成部分:抽象工厂类,具体工厂类,抽象产品类,具体产品类四部分组成。
首先,我们介绍下两个概念:产品簇:具体例子:MySQL,SQLserver,Oracle等都提供相似的功能,拥有相似的结构。产品等级:举个例子:各个数据库的版本。
由上面的示例可以总结出,在抽象工厂模式中,扩展一个产品簇是相对容易的。但是,如果要扩展一个产品等级,意味着需要对所有的具体类都进行相关功能的实现。
因此,在应用该模式时,需要实现设计好各种产品等级,随着时间推进,如果需要新增一个产品等级,工作量非常的巨大。希望各位看官牢记。
需要将对象的应用与创建及细节进行屏蔽时。
需要使用一个产品簇,但是每次只会使用一个具体的产品时。
在这个产品簇内,拥有相似的功能和特征。
产品簇结构稳定,不会轻易修改。
客户端不关心具体的产品的创建及对象细节,其面向接口编程。
保证产品簇中只能示例话出一个实例。
一定程度上符合“开闭原则”
不适合产品等级随时变化的场景。
如果发生切换,不仅工厂需要修改,客户端也需要切换到对应的声明上。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---抽象工厂模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445
本文,我们讲介绍抽象工厂模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:
操作系统:win7
x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------
经典问题:
在产品簇的范围内选择合适对象的问题,如数据库驱动。(产品簇:相同功能的不同实例)
思路分析:
要点一:所有产品具有相似的功能或属性。要点二:所有产品在实现上存在差异。
示例工程:
错误写法:
创建SqlDB.java文件,具体内容如下:(在此为简化实现过程,实际代码仅作为示例,简单的SQL连接代码,见注释部分)package com.csdn.ingo.gof_AbstractFactory; public class SqlDB { public void insert(User user){ System.out.println("insert:"+user.getName()); } public User select(String string){ System.out.println("select:"+string); return null; } } //public class DBConnection { // public static final String url = "jdbc:mysql://127.0.0.1/student"; // public static final String name = "com.mysql.jdbc.Driver"; // public static final String user = "root"; // public static final String password = "root"; // // public Connection conn = null; // public PreparedStatement pst = null; // // public DBConnection(String sql) { // try { // Class.forName(name);//指定连接类型 // conn = DriverManager.getConnection(url, user, password);//获取连接 // pst = conn.prepareStatement(sql);//准备执行语句 // } catch (Exception e) { // e.printStackTrace(); // } // } // // public void close() { // try { // this.conn.close(); // this.pst.close(); // } catch (SQLException e) { // e.printStackTrace(); // } // } //}创建User.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory; public class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory; public class Window { public static void main(String[] args) { User u = new User(); SqlDB s = new SqlDB(); u.setId("aaaa"); u.setName("bbbb"); s.insert(u); s.select("aaaa"); } }
错误原因:
数据库的选择直接写入代码,并且与Sql语句的耦合度非常高。一旦后期进行适配别的数据库,就会违反“开闭原则”,从而需要大量的工作才能修改到对应的数据库,并且这种修改的影响范围的深度与广度尚未可知。因此,这种代码书写方式是一种非常不好的书写方式。
工厂方法模式的实现:
在前文中,我们介绍了工厂方法模式,在此,我们先来看看使用工厂方法模式的实现过程。创建IFactory.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public interface IFactory { public IUser createUser(); }创建AccessFactory.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public class AccessFactory implements IFactory { public IUser createUser() { return new AccessUser(); } }创建SqlserverFactory.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public class SqlserverFactory implements IFactory{ public IUser createUser() { return new SqlserverUser(); } }创建IUser.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public interface IUser { void insert(User u); User select(String id); }创建AccessUser.java,SqlserverUser.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public class AccessUser implements IUser{ public void insert(User user){ System.out.println("insert:"+user.getName()); } public User select(String string){ System.out.println("select:"+string); return null; } }创建User.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.one; public class Window { public static void main(String[] args) { User u = new User(); u.setName("aaaa"); IFactory f = new SqlserverFactory(); IUser iu = f.createUser(); iu.insert(u); iu.select("aaa"); } }工厂方法实现的优点与不足:
优点:切换数据时,仅需修改IFactory f = new SqlserverFactory();及对应的SQL语句。
缺点:任何新增和修改,都可能会导致需要针对不同的数据库进行对应的实现。
推荐写法:(抽象工厂模式)
详细代码与上文类似,工程结构图见下文模式总结部分。
在抽象工厂实现的基础上,结合简单工厂模式在进行略微修改:
创建DateAccess.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.three; public class DataAccess { // private static final String db = "Sqlserver";//可由配置文件实现 private static final String db = "Access"; public static IUser createUser() { IUser re = null; switch (db) { case "Sqlserver": re = new SqlserverUser(); break; case "Access": re = new AccessUser(); break; default: break; } return re; } public static IDepartment createDepartment() { IDepartment re = null; switch (db) { case "Sqlserver": re = new SqlserverDepartment(); break; case "Access": re = new AccessDepartment(); break; default: break; } return re; } }创建IUser.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.three; public interface IUser { void insert(User u); User select(String id); }创建IDepartment.java文件,具体内容如下;
package com.csdn.ingo.gof_AbstractFactory.three; public interface IDepartment { void insert(Department d); Department select(String id); }创建SqlserverUser.java,AccessUser.java,SqlserverDepartment.java,AccessDepartment.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.three; public class SqlserverUser implements IUser { public void insert(User user){ System.out.println("SqlserverUser insert:"+user.getName()); } public User select(String string){ System.out.println("SqlserverUser select:"+string); return null; } }创建User.java,Department.java文件,见上文。
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.three; import org.omg.PortableServer.IdAssignmentPolicy; public class Window { public static void main(String[] args) { User u = new User(); u.setName("aaaa"); IUser iu = DataAccess.createUser(); iu.insert(u); iu.select("aaa"); Department de = new Department(); de.setName("asdf"); IDepartment d = DataAccess.createDepartment(); d.insert(de); d.select("asdf"); } }
推荐原因:
具体的Factory实现类,直到运行时才确定,并且,这个具体的Factory负责创建具体的对象。客户端如需要不同的对象,就需要调用不同的具体工厂。由此,在切换时,可以跟方便的切换调用方式即可。因为,客户端是面向抽象的,具体的实现已经分离到具体的子类当中。中间通过抽象接口作为中介,对于客户端完全屏蔽。非常符合“开闭原则”“迪米特法则”等。最后,上面的功能其实已经足够说明抽象工厂模式,简单工厂模式,工厂方法模式的区别了。但在此,为了完整的展示三种工厂模式的强大功能,我们再将配置文件与反射的结合的代码给出,供各位看官学习。创建Init.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.four; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class Init { public static Properties getPro() throws FileNotFoundException, IOException { InputStream inputStream =Object.class.getResourceAsStream("/classpro.properties"); Properties pro = new Properties(); pro.load(inputStream); return pro; } }在resources文件夹下,创建classpro.properties文件,具体内容如下:
User=com.csdn.ingo.gof_AbstractFactory.four.AccessUser Department=com.csdn.ingo.gof_AbstractFactory.four.SqlserverDepartment创建UserFactory.java,DepartmentFactory.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.four; public class UserFactory { public static IUser getInstance(String className) { IUser u = null; try { u = (IUser) Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return u; } }创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_AbstractFactory.four; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; import org.omg.PortableServer.IdAssignmentPolicy; public class Window { public static void main(String[] args) throws FileNotFoundException, IOException { Properties pro = Init.getPro(); User u = new User(); u.setName("aaaa"); IUser iu = UserFactory.getInstance(pro.getProperty("User")); iu.insert(u); iu.select("aaa"); Department de = new Department(); de.setName("asdf"); IDepartment d = DepartmentFactory.getInstance(pro.getProperty("Department")); d.insert(de); d.select("asdf"); } }其他文件请参考上文工程。现在,对于任意功能的数据访问层切换都可以完全脱离修改源代码。极大的方便了后期的维护与扩展。
模式总结:
本例UML结构图:标准抽象工厂模式UML结构图:
概念总结:
抽象工厂模式:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。组成部分:抽象工厂类,具体工厂类,抽象产品类,具体产品类四部分组成。
反思:
首先,我们介绍下两个概念:产品簇:具体例子:MySQL,SQLserver,Oracle等都提供相似的功能,拥有相似的结构。产品等级:举个例子:各个数据库的版本。由上面的示例可以总结出,在抽象工厂模式中,扩展一个产品簇是相对容易的。但是,如果要扩展一个产品等级,意味着需要对所有的具体类都进行相关功能的实现。
因此,在应用该模式时,需要实现设计好各种产品等级,随着时间推进,如果需要新增一个产品等级,工作量非常的巨大。希望各位看官牢记。
应用场景:
需要将对象的应用与创建及细节进行屏蔽时。需要使用一个产品簇,但是每次只会使用一个具体的产品时。
在这个产品簇内,拥有相似的功能和特征。
产品簇结构稳定,不会轻易修改。
优点:
客户端不关心具体的产品的创建及对象细节,其面向接口编程。保证产品簇中只能示例话出一个实例。
一定程度上符合“开闭原则”
缺点:
不适合产品等级随时变化的场景。如果发生切换,不仅工厂需要修改,客户端也需要切换到对应的声明上。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---抽象工厂模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445
相关文章推荐
- 设计模式C#描述——抽象工厂模式
- .NET设计模式-抽象工厂模式(Abstract Factory)
- 设计模式C#描述——抽象工厂模式
- 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)
- 设计模式——创建型模式之 Abstract Factory抽象工厂模式
- [导入]C#面向对象设计模式纵横谈(3):Abstract Factory 抽象工厂模式(创建型模式)
- 设计模式C#描述——抽象工厂模式
- Java设计模式圣经连载(03)-抽象工厂模式
- 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)
- 我的设计模式之旅(3)――抽象工厂模式AbstractFactory
- 设计模式实践(抽象工厂模式应用)—通信录的优化过程
- 设计模式之抽象工厂模式
- AspectJ实现设计模式(四)——抽象工厂模式
- .NET设计模式:抽象工厂模式(Abstract Factory)
- [导入]C#面向对象设计模式纵横谈(4):Abstract Factory 抽象工厂模式(创建型模式)
- 设计模式笔记-抽象工厂模式
- .Net设计模式之抽象工厂模式(Abstract Factory)
- .NET设计模式(3):抽象工厂模式(Abstract Factory)(转)
- 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)
- 设计模式(3)-抽象工厂模式(Abstract Factory)