建设银行重庆市分行官方网站vs 2008 手机网站开发
news/
2025/9/30 17:42:32/
文章来源:
建设银行重庆市分行官方网站,vs 2008 手机网站开发,贵州手机网站建设,莱芜论坛都市网目录 概述概念适用场景结构类图 衍化过程业务需求基本的数据访问程序工厂方法实现数据访问程序抽象工厂实现数据访问程序简单工厂改进抽象工厂使用反射抽象工厂反射配置文件衍化过程总结 常见问题总结 概述
概念 抽象工厂模式是一种创建型设计模式#xff0c;它提供了一种将相… 目录 概述概念适用场景结构类图 衍化过程业务需求基本的数据访问程序工厂方法实现数据访问程序抽象工厂实现数据访问程序简单工厂改进抽象工厂使用反射抽象工厂反射配置文件衍化过程总结 常见问题总结 概述
概念 抽象工厂模式是一种创建型设计模式它提供了一种将相关对象组合在一起创建的方式而无需指定具体类。该模式通过定义一个抽象工厂接口来创建一系列相关或依赖的对象而不是直接实例化具体类。这种方式使得系统更加灵活易于扩展和维护。
适用场景
抽象工厂模式适用于以下情况
当一个系统需要独立于其产品的创建、组合和表示时 当一个系统需要由多个系列的产品中的一个进行配置时 当强调一系列相关产品对象的创建和一起使用时 当提供一个产品类库而只想显示它们的接口而不是实现时。
结构
抽象工厂模式包含以下几个角色
抽象工厂Abstract Factory声明了创建一系列产品对象的接口。 具体工厂Concrete Factory实现了抽象工厂接口具体工厂负责创建具体的产品对象。 抽象产品Abstract Product声明了具体产品的接口。 具体产品Concrete Product实现了抽象产品接口具体产品是由具体工厂创建的。
类图 衍化过程
业务需求 假设有一个简单的应用程序它使用了 SQL Server 数据库来存储数据。现在需要将数据库更换为 Access 数据库同时保持应用程序的功能不变。
基本的数据访问程序 客户端直接和qlserverUser耦合
//SqlServer
public class SqlServerUser {//新增用户public void insert(User user){System.out.println(在SQlServer中给USER表添加一条数据);}//获取用户信息public User getUser(int id){System.out.println(在SQlServer中根据用户id得到USER表中的一条记录);return null;}
}//user表
public class User {private int _id;public int getid(){return this._id;}public void setId(int value){this._idvalue;}private String _name;public String getname(){return this._name;}public void setname(String value){this._namevalue;}
}//客户端
public class Client {public static void main(String[] args) {User usernew User();SqlServerUser sunew SqlServerUser();su.insert(user);su.getUser(1);}
}在这段客户端代码中可以看到SqlServerUser sunew SqlServerUser();使su这个对象被框死在了SqlServerUser上。 现在要做的就是解除客户端和SqlServerUser 的耦合(简答说就是客户端不再依赖SqlServerUser 那么更换其他的数据库管理系统就不会影响应用程序了)
工厂方法实现数据访问程序 解除客户端和SqlServerUser对象的耦合就是把 new SqlServerUser()封装起来这点上想到使用工厂方法封装new SqlServerUser()过程。
抽出两个接口
//工厂接口
interface IFactory {public IUser creatUserDB();}
//数据库接口
public interface IUser {public void insert(User user);public User getUser(int id);
}//SqlServerUser 用于访问SqlServer的User
public class SqlServerUser implements IUser {//新增用户Overridepublic void insert(User user) {System.out.println(在SQlServer中给USER表添加一条数据);}public User getUser(int id){System.out.println(在SQlServer中根据用户id得到USER表中的一条记录);return null;}
}
//SqlServerFactory 实例化SqlServerUser
public class SqlServerFactory implements IFactory {Overridepublic IUser creatUser() {return new SqlServerUser();}
}//客户端
public static void main(String[] args) {Ifactory factorynew SqlServerFactory();User usernew User();IUser iu factory.creatUser();iu.insert(user);iu.getUser(1);}再来看客户端声明IUser接口的对象iu事先并不知道要访问哪个数据库却可以在运行时完成工作这就是业务逻辑和数据访问的解耦(也就是客户端不再依赖SqlServerUser如果需要更换AccessUser只需要创建一个AccessFactory由AccessFactory封装创建AccessUser对象的过程。) 现在又有了新的问题 数据库里如果不是只有一个User表呢该怎么办
抽象工厂实现数据访问程序 现在需要增加一个Department表SqlServer和Access分别操作这个Department表 再抽出一个IDepartment的接口两个工厂了分别增加创建SqlserverDepartment和AccessDepartment的方法 工厂里两个方法可以有不同的实现可以理解为两个不同的系列
//工厂接口
public interface IFactory {public IUser creatUserDB();public IDepartment createDepartment();
}
//客户端
public class Client {public static void main(String[] args) {//需要对两个表操作,客户端只认识两个表不认识Access和SQLServerUser user new User();Department department new Department();//需要用哪个DBMS就实例化哪个工厂IFactory factory new SqlServerFactory();//实例化数据库交给对应的工厂IUser iu factory.creatUserDB();//user表里插入读取操作iu.getUser(1);iu.insert(user);IDepartment ideptfactory.createDepartment();//department表里插入读取操作idept.getDepartment(2);idept.insert(department);}
}再分析一下需求我们是要读写User表和Department表IUser和IDepartment里有对应的方法也就是干活的是这两个接口的实现类SqlServerUser、AccessUser以及SqlServerDepartment、AccessDepartment那谁负责生产这些实现类的对象呢那就看谁的返回对象是IUser和IDepartment当然是工厂SqlServerFactory和AccessFactory. 抽象工厂的优势现在体现出来了 1、易于交换产品系列 由于具体工厂类例如Factory factorynew AccessFactory0, 在一个应用中只需要在初始化的时候出现一次这就使得改变一个应用的具体工厂变得非常容易它只需要改变具体工厂即可使用不同的产品配置。 我们的设计不能去防止需求的更改那么我们的理想便是让改动变得最小 2、它让具体的创建实例过程与客户端分离这点工厂方法也做到了 客户端是通过它们的抽象接口操纵实例产品的具体类名也被具体工厂的实现分离不会出现在客户代码中。事实上客户端所认识的只有User和Department,至于它是用SQL Server来实现还是Access来实现就不知道了。” 但是仍然存在的问题 1、业务扩充 要增加项目表Project,至少要增加三个类IProject、.SqlserverProject、AccessProject,.还需要更改IFactory、SqlserverFactory和AccessFactory才可以完全实现。对应两个表的两个dbms两个生产dbms的工厂还有两个接口 2、客户端如果多个改动就很多 有很多地方使用IUesr或Department,而这样的设计其实在每一个类的开始都需要声明Factory factorynew SqlserverFactory0,如果有100个调用数据库访问的类就要更改l00次Factory factorynew AccessFactory()这样的代码
简单工厂改进抽象工厂 抽象工厂客户端耦合太多 去掉工厂创建对象交给DateAccess
//DataAccess 负责创建具体数据库对象
public class public class DataAccess {private static String dbSqlserver;//可换成Access//创建用户对象工厂public static IUser createUser(){IUser resultnull;switch (db){case Sqlserver:resultnew SqlServerUser();break;case Access:resultnew AccessUser();break;}return result;}//创建部门对象工厂public static IDepartment createDepartment(){IDepartment resultnull;switch (db){case Sqlserver:resultnew SqlServerDepartment();break;case Access:resultnew AccessDepartment();break;}return result;}}
{private static String dbSqlserver;//可换成Access//创建用户对象工厂public static IUser createUser(){IUser resultnull;switch (db){case Sqlserver:resultnew SqlServerUser();break;case Access:resultnew AccessUser();break;}return result;}//创建部门对象工厂public static IDepartment createDepartment(){IDepartment resultnull;switch (db){case Sqlserver:resultnew SqlServerDepartment();break;case Access:resultnew AccessDepartment();break;}return result;}}//客户端
public class Client {public static void main(String[] args) {//需要对两个表操作,客户端只认识两个表不认识Access和SQLServerUser user new User();Department department new Department();//实例化数据库交给DataAccessIUser iu DataAccess.createUser();//user表里插入读取操作iu.getUser(1);iu.insert(user);IDepartment ideptDataAccess.createDepartment();//department表里插入读取操作idept.getDepartment(2);idept.insert(department);}
}问题 如果需要增加Oracle数据库访问抽象工厂只增加一个OracleFactory工厂类就可以了现在就需要在DataAccess类中每个方法的swicth中加case 改进 不在程序里写明‘如果是Sqlserver就去实例化SQL Server数据库相关类如果是Access就去实例化Access相关类’这样的语句而是根据字符串db的值去某个地方找应该要实例化的类是哪一个。这样就不用switch case了
使用反射抽象工厂
类图只改变DataAccess就可以
public class DataAccess {private static String assemblyNamedesignpatterns.abstractfactory.reflaxAbstractFactoryAccess.DB.;private static String dbSqlServer;//数据库名称可替换为Access//创建用户对象工厂public static IUser createUser(){return (IUser)getInstance(assemblyNamedbUser);}//创建部门对象工厂public static IDepartment createDepartment(){return (IDepartment) getInstance(assemblyNamedbDepartment);}private static Object getInstance(String className){Object resultnull;try {resultClass.forName(className).getDeclaredConstructor().newInstance();}catch(InvocationTargetException e){e.printStackTrace();}catch(NoSuchMethodException e){e.printStackTrace();}catch(InstantiationException e){e.printStackTrace();}catch(IllegalAccessException e){e.printStackTrace();}catch(ClassNotFoundException e){e.printStackTrace();}return result;}}对象可以根据类路径动态创建了但是在更换数据库访问时还是需要去改程序改db这个字符串的值重编译如果可以不改程序那才是真正地符合开放-封闭原则。
反射配置文件
相对于只用反射属性db数据库名动态获取了
public class DataAccess {private static String assemblyNamedesignpatterns.abstractfactory.profileReflaxAbstractFactoryAccess.DB.;public static String getDb() throws IOException {String result;Properties propertiesnew Properties();properties.load(new FileInputStream(E:\\tgb\\training program\\java\\myProject\\src\\main\\java\\designpatterns\\abstractfactory\\profileReflaxAbstractFactoryAccess\\db.properties));resultproperties.getProperty(db);return result;}//创建用户对象工厂public static IUser createUser() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {String dbgetDb();return (IUser)getInstance(assemblyNamedbUser);}
//反射获取对象public static IDepartment createDepartment() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {String dbgetDb();return (IDepartment) getInstance(assemblyNamedbDepartment);}private static Object getInstance(String className) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Object resultnull;resultClass.forName(className).getDeclaredConstructor().newInstance(); return result;}}进步 如果更换数据库无须重新编译代码只需要改配置文件就可以。 所有在用简单工厂的地方都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合。” 反射技术可以很好地解决switch 或者if分支难以应对变化难以维护和扩展的诟病。
衍化过程总结 在上面的示例中业务需求是通过数据库连接来执行查询操作。一开始使用了简单的数据访问方式直接在应用程序中编写了连接和查询数据库的代码。 随着业务的发展需要将数据库从 SQL Server 更换为 Access。为了实现这个数据库更换的需求采用了工厂方法模式。通过引入抽象产品IUser和具体产品SqlServerUser和AccessUser抽象工厂IFactory和具体工厂SqlServerFactory和AccessFactory将数据库连接的创建和使用进行了解耦使得代码更加灵活和可扩展。 然后需要增加一个部门表让两个数据库去访问为了应对这种变化引入了抽象工厂模式。通过在具体工厂SqlServerFactory和AccessFactory中增加一个creatDepartment方法解决了创建SqlServerDepartment和AccessDepartment的问题。 后面又为了更加灵活介绍了用简单工厂来改进抽象工厂以及使用反射和配置文件真正实现三高。 每次的变化都是为了应对业务需求的不断变化。最初的简单数据访问方式可能适应了当时的需求但随着业务的发展和技术环境的变化需要更灵活、可扩展的解决方案。工厂方法和抽象工厂模式提供了一种可扩展的设计使得我们能够快速适应业务变化并以相对低的开销进行数据库类型的切换。
常见问题
什么是一系列相关或依赖的对象 一系列相关或相互依赖的对象指的是一组具有共同特征或者相互之间存在某种关联关系的对象集合。这些对象通常有着相似或者相互关联的功能、属性或行为。 如何判断这些对象是一系列相关或相互依赖的呢 共同特征这些对象具有共同的特征或者属性。例如它们可能都实现了同一个接口或者继承了同一个抽象类并拥有类似的方法或属性。 相互关联这些对象之间存在某种关联关系彼此之间相互依赖。例如它们可能是一种逻辑上或功能上相关的对象需要协同工作以完成某个复杂的任务。 执行步骤这些对象在特定的操作过程中需要按照一定的顺序或流程进行调用。它们可能是按照特定的顺序被创建、初始化、配置或者销毁的。 统一管理这些对象可能需要由同一个抽象工厂来创建和管理。抽象工厂可以提供一种统一的方式来创建这些对象确保它们之间的协调性和一致性。 总之一系列相关或相互依赖的对象在抽象工厂模式中是作为一个整体出现的它们具有共同特征、相互关联需要按照一定顺序进行操作并由同一个抽象工厂进行创建和管理。这样可以更好地实现对象之间的协作和组织。 举个栗子 比如有一个一个汽车制造厂可以使用抽象工厂模式来创建一系列相关或相互依赖的对象。 假设汽车制造厂需要生产不同类型的汽车如轿车Sedan和SUVSport Utility Vehicle。每种类型的汽车由多个部件构成包括引擎Engine、底盘Chassis和车身Body等。
在这个例子中可以定义以下抽象类和接口
CarFactory抽象工厂定义了用于创建汽车部件的方法。Engine抽象产品定义了引擎的功能。Chassis抽象产品定义了底盘的功能。Body抽象产品定义了车身的功能。
具体的类可以包括 SedanCarFactory具体工厂实现了CarFactory接口并负责创建轿车相关的部件。 SedanEngine具体产品实现了Engine接口提供了轿车引擎的具体功能。 SedanChassis具体产品实现了Chassis接口提供了轿车底盘的具体功能。 SedanBody具体产品实现了Body接口提供了轿车车身的具体功能。 SuvCarFactory具体工厂实现了CarFactory接口并负责创建SUV相关的部件。 SuvEngine具体产品实现了Engine接口提供了SUV引擎的具体功能。 SuvChassis具体产品实现了Chassis接口提供了SUV底盘的具体功能。 SuvBody具体产品实现了Body接口提供了SUV车身的具体功能。 在这个例子中抽象工厂模式将一系列相关或相互依赖的对象引擎、底盘和车身组合到具体的工厂中轿车工厂和SUV工厂。每个具体工厂负责创建特定类型汽车所需的部件并保证这些部件之间的协调性和一致性。 例如当需要生产一辆轿车时可以使用SedanCarFactory创建引擎、底盘和车身。而当需要生产一辆SUV时可以使用SuvCarFactory创建相应的部件。 通过使用抽象工厂模式汽车制造厂可以轻松扩展以生产不同类型的汽车而无需修改现有代码。同时不同类型的汽车部件之间的依赖关系也得到了良好的管理和维护提高了系统的可维护性和可扩展性。
总结 抽象工厂模式通过引入抽象工厂接口使得客户端代码与具体产品的实现解耦。它提供了一种简单的方式来创建一系列相关的产品对象而无需关心具体的实现细节。通过选择不同的具体工厂可以轻松地切换不同的产品系列以满足不同的需求。抽象工厂模式在大型系统中非常有用它能够提高代码的可维护性、可扩展性和可测试性。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/923107.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!