抽象工厂模式
来源:互联网 发布:电脑机箱背板孔位数据 编辑:程序博客网 时间:2024/04/30 01:12
书中引例:项目用的数据库为 SQL Server 。后又需求换成 Access 。数据库都有读写查等共同的操作,
using UnityEngine;using System.Collections;public class AbstractFactoryStudy : MonoBehaviour {// Use this for initializationvoid Start () { User user = new User();// IFactory07 factory07 = new SqlSercerFactory(); 若要换数据库 这两句换一下就行了 IFactory07 factory07 = new AccessFactory(); IUser iu = factory07.CreatUser(); iu.Insert(user); iu.GetUser(1);}}//IUser 接口 ,用于客户端访问,解除与具体数据库访问的耦合。public interface IUser{ void Insert(User user); User GetUser(int id);}//SqlsercerUser 用于访问SqlServer的Userpublic class SqlsercerUser : IUser{ public void Insert(User user) { Debug.Log("在SQL中添加记录"); } public User GetUser(int id) { Debug.Log("在SQL中获得记录"); return null; }}//AccesssUser 用于访问Access的Userpublic class AccesssUser : IUser { public void Insert(User user) { Debug.Log("在AccesssUser中添加记录"); } public User GetUser(int id) { Debug.Log("在AccesssUser中获得记录"); return null; }}//IFactory07 接口, 定义一个创建访问User表对象的抽象的工厂接口。 public interface IFactory07{ IUser CreatUser();}//SqlSercerFactory 类,实现 IFactory07 接口,实例化 SqlsercerUserpublic class SqlSercerFactory :IFactory07{ public IUser CreatUser() { return new SqlsercerUser(); }}//AccessFactory 类,实现 IFactory07 接口,实例化 AccessUserpublic class AccessFactory : IFactory07 { public IUser CreatUser() { return new AccesssUser(); }}//User 表结构public class User{ public int ID { get; set; } public string name { get; set; }}
以上想想要换数据库只需要改一句就行了,由于多肽的关系,使得声明的 IUSer 接口的对象 iu 事先根本不知道是在访问那个数据库,却可以在运行时很好的完成工作,实现了业务逻辑与数据访问的解耦。
需要加一个数据库表 Department:
using UnityEngine;using System.Collections;public class AbstractFactoryStudy : MonoBehaviour {// Use this for initializationvoid Start () { User user = new User();// IFactory07 factory07 = new SqlSercerFactory(); 若要换数据库 这两句换一下就行了 IFactory07 factory07 = new AccessFactory(); IUser iu = factory07.CreatUser(); iu.Insert(user); iu.GetUser(1); Department dept = new Department(); IDepartment id = factory07.CreatDepartment(); id.Insert(dept); id.GetDepartment(1);}}public interface IDepartment{ void Insert(Department department); Department GetDepartment(int id );}public interface IUser{ void Insert(User user); User GetUser(int id);}public class SqlsercerDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class SqlsercerUser : IUser{ public void Insert(User user) { Debug.Log("在SQL中添加记录"); } public User GetUser(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssUser : IUser { public void Insert(User user) { Debug.Log("在AccesssUser中添加记录"); } public User GetUser(int id) { Debug.Log("在AccesssUser中获得记录"); return null; }}public interface IFactory07{ IUser CreatUser(); IDepartment CreatDepartment();// 增加接口的方法}public class SqlSercerFactory :IFactory07{ public IUser CreatUser() { return new SqlsercerUser(); } public IDepartment CreatDepartment()//增加了 SqlsercerDepartment 工厂 { return new SqlsercerDepartment(); }}public class AccessFactory : IFactory07 { public IUser CreatUser() { return new AccesssUser(); } public IDepartment CreatDepartment()//增加了 AccesssDepartment 工厂 { return new AccesssDepartment(); }}public class User{ public int ID { get; set; } public string name { get; set; }}//Department 表结构public class Department { public int ID { get; set; } public string name { get; set; }}
抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口, 而无需指定他们具体的类。
AbstractProductA 和 AbstractProductB 是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现,就刚才的例子来说就是User 和 Department ,而 ProductA1 ProductA2 和 ProductB1 ProductB2 就是对两个抽象产品的具体分类的实现,比如ProductA1可以理解为是 SqlServerUser ,而 ProductB1 是 AccessUser。
IFactory 是一个抽象工厂接口, 它里面应该包含所有的产品创建的抽象方法。而 ConcreteFactory1 和 ConcreteFactory2 就是具体的工厂了,就像 SqlserverFactory 和 AccessFactory 一样。 通常是子啊运行时刻在创建一个ConcreteFactory 类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。
优点:易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。
缺点:如果现在又需要加入表 Project 的话,那么至少要增加三个类:IProject SqlserverProject AccessProject 还需要更改 IFactory SqlserverFactory 和 AccessFactory 才可以完全实现。
客户端类并不只有一个,也就是调用IUser 或 IDepartment ,的地方都需要声明 IFactory factory = new AccessFactory(),要换数据库的话 每个地方都要改,所以 可以用简单工厂来改进抽象工厂, 去除 IFactory SqlserverFactory 和 AccessFactory 三个工厂类。 取而代之的是 DataAccess 类, 用一个简单工厂模式来实现。
using UnityEngine;public class AbstractFactoryStudy : MonoBehaviour {// Use this for initializationvoid Start () { User user = new User(); Department dept = new Department(); //直接得到实际的数据库访问实例,而不存在任何依赖。 IUser iu = DataAccess.CreateUser(); iu.Insert(user); iu.GetUser(1); //直接得到实际数据库访问实例,而不存在任何依赖 IDepartment id = DataAccess.CreateDepartment(); id.Insert(dept); id.GetDepartment(1);}}public class DataAccess{ private static readonly string db = "Sqlserver";// private static readonly string db = "Access"; 数据库名称可替换 public static IUser CreateUser() { IUser result = null; switch (db) { case "Sqlserver": result = new SqlsercerUser(); break; case "Access": result = new AccesssUser(); break; } return result; } public static IDepartment CreateDepartment() { IDepartment result = null; switch (db) { case "Sqlserver": result = new SqlsercerDepartment(); break; case "Access": result = new AccesssDepartment(); break; } return result; }}public interface IDepartment{ void Insert(Department department); Department GetDepartment(int id );}public interface IUser{ void Insert(User user); User GetUser(int id);}public class SqlsercerDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class SqlsercerUser : IUser{ public void Insert(User user) { Debug.Log("在SQL中添加记录"); } public User GetUser(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssUser : IUser { public void Insert(User user) { Debug.Log("在AccesssUser中添加记录"); } public User GetUser(int id) { Debug.Log("在AccesssUser中获得记录"); return null; }}public class User { public int ID { get; set; } public string name { get; set; }}//Department 表结构public class Department { public int ID { get; set; } public string name { get; set; }}
上述代码抛弃了 IFactory SqlserverFactory 和 AccessFactory 三个工厂类,取而代之的是 DataAccess类,由于事先设置了db的值(Sqlserver 或 Access),所以简单工厂的方法都不需要传入参数,客户端没有出现任何一个 SQLServer 或 Access 的字样,达到了解耦的目的。
如果再需要加入Oracle数据库的访问的话 需要在DataAccess 类中每个方法的switch 中加case 也比较繁琐,可以利用反射来改进:
Assembly.Load("程序集名称").CreatInstance("命名空间.类名称")
反射引用的命名空间: using System.Reflection;
备注: ReadOnly与Const区别
using UnityEngine;using System.Reflection;public class AbstractFactoryStudy : MonoBehaviour {void Start () { User user = new User(); Department dept = new Department(); IUser iu = DataAccess.CreateUser(); iu.Insert(user); iu.GetUser(1); IDepartment id = DataAccess.CreateDepartment(); id.Insert(dept); id.GetDepartment(1);}}public class DataAccess{ private static readonly string AssemblyName = "DaHuaSheJi"; private static readonly string db = "Sqlserver";//可换成 Access。 变化时 之变化这一句就可以了 public static IUser CreateUser() { string className = AssemblyName + "." + db + "User"; return (IUser) Assembly.Load(AssemblyName).CreateInstance(className);/* Unity 中这样写 Type t = Type.GetType("SqlsercerUser"); return (IUser) Activator.CreateInstance(t);*/ }
public static IDepartment CreateDepartment() { IDepartment result = null; switch (db) { case "Sqlserver": result = new SqlsercerDepartment(); break; case "Access": result = new AccesssDepartment(); break; } return result; }}public interface IDepartment{ void Insert(Department department); Department GetDepartment(int id );}public interface IUser{ void Insert(User user); User GetUser(int id);}public class SqlsercerDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssDepartment : IDepartment { public void Insert(Department department) { Debug.Log("在SQL中添加记录"); } public Department GetDepartment(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class SqlsercerUser : IUser{ public void Insert(User user) { Debug.Log("在SQL中添加记录"); } public User GetUser(int id) { Debug.Log("在SQL中获得记录"); return null; }}public class AccesssUser : IUser { public void Insert(User user) { Debug.Log("在AccesssUser中添加记录"); } public User GetUser(int id) { Debug.Log("在AccesssUser中获得记录"); return null; }}public class User { public int ID { get; set; } public string name { get; set; }}//Department 表结构public class Department { public int ID { get; set; } public string name { get; set; }}
以上 ,如果在需要增加 Project 产品时,只需要增加三个与 Project 相关的类,在修改 DataAccess ,在其中增加一个 public static IProject CreatProject() 方法就可以了。
在追求完美一下, 就是将要读的数据库名称字符串放到配置文件中,添加一个 App.config文件,内容下:
<?xml version="1.0" encoding="utf-8" ?><configuration> <addSettings> <add key="DB" value="Sqlserver"/> </addSettings></configuration>
所有的简单工厂都可以考虑用反射技术来去除 switch 或 if 解除分支判断带来的耦合。
- 工厂模式 -- 抽象工厂
- 工厂模式-抽象工厂
- 工厂模式-抽象工厂
- 工厂模式/抽象工厂模式
- 工厂模式&&抽象工厂模式
- 工厂模式---抽象工厂模式
- 工厂模式&抽象工厂模式
- 工厂模式,抽象工厂模式
- 【模式】抽象工厂模式
- 简单工厂、工厂模式、抽象工厂模式
- 简单工厂、工厂模式、抽象工厂模式
- 简单工厂&工厂模式&抽象工厂模式
- 工厂方法,抽象工厂模式
- 2,工厂模式--抽象工厂
- C#工厂模式-抽象工厂
- 工厂模式与抽象工厂
- 抽象工厂设计模式
- 抽象工厂模式
- 测试分析例子--杯子,圆珠笔
- mybatis的动态sql和关联查询
- 代码规范
- GIT添加代码到服务器操作
- Linux进程通信共享内存
- 抽象工厂模式
- springsecurity4.2入门完整实例
- js判断json对象是否为空
- Java 好看的label-textfield(-button)布局
- django static_root static_url media_root mdia_url详解
- 功分器,双工器,耦合器,合路器,环形器
- Spring Security# Multiple DaoAuthenticationProvider
- java之枚举的使用方法
- 《Windows核心编程》读书笔记四 进程