抽象工厂模式【实例】:
定义一个用于创建对象的接口,让子类决定实例化哪一个类

UML

代码
class User
{
    private int _id;
    public int Id { get => _id; set => _id = value; }

private string _name;
    public string Name { get => _name; set => _name = value; }
}

interface IUser
{
   void Insert(User user);
   User GetUser(int id);
}

class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在SQL Server中给User表增加一条记录");
    }

public User GetUser(int id)
   {
      Console.WriteLine("在SQL Server中根据ID得到User表一条记录");
      return null;
   }
}

class SqlServerFactory : IFactory
{
    public IUser CreateUser()
    {
        return new SqlserverUser();
    }
}

class AccessUser : IUser
{
    public User GetUser(int id)
   {
       Console.WriteLine("在Access中根据ID得到User表一条记录");
       return null;
   }

public void Insert(User user)
   {
       Console.WriteLine("在Access中给User表增加一条记录");
   }
}

class AccessFactory : IFactory
{
    public IUser CreateUser()
   {
        return new AccessUser();
   }
}

// test
User user = new User();
//IFactory factory = new SqlServerFactory();
IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);

// result
在Access中给User表增加一条记录
在Access中根据ID得到User表一条记录

抽象工厂模式(Abstract Factory)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

UML

代码
class Department
{
      private string name;
      private string id;

public string Name { get => name; set => name = value; }
      public string Id { get => id; set => id = value; }
}

interface IDepartment
{
     void Insert(Department department);
     Department GetDepartment(int id);
}

class SqlserverDepartment : IDepartment
{
    public void Insert(Department department)
    {
         Console.WriteLine("在SQL Server中给Department表增加一条记录");
    }

public Department GetDepartment(int id)
   {
       Console.WriteLine("在SQL Server中根据ID得到Department表一条记录");
       return null;
   }
}

class AccessDepartment : IDepartment
{
    public Department GetDepartment(int id)
   {
        Console.WriteLine("在Access中根据ID得到Department表一条记录");
        return null;
   }

public void Insert(Department department)
   {
        Console.WriteLine("在Access中给Department表增加一条记录");
   }
}

class SqlServerFactory : IFactory
{
    public IUser CreateUser()
     {
        return new SqlserverUser();
     }

public IDepartment CreateDepartment()
   {
      return new SqlserverDepartment();
   }
}
class AccessFactory : IFactory
{
   public IUser CreateUser()
   {
       return new AccessUser();
   }

public IDepartment CreateDepartment()
   {
        return new AccessDepartment();
   }
}

// test
User user = new User();
Department dept = new Department();

//IFactory factory = new SqlServerFactory();
IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);

IDepartment id = factory.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);

// result
在Access中给User表增加一条记录
在Access中根据ID得到User表一条记录
在Access中给Department表增加一条记录
在Access中根据ID得到Department表一条记录

IFactory 就是一个抽象工厂接口,它里面应该包含所有的产品创建的抽象方法
通常在运行时再创建一个ConcreteFactory类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说为创建不同的产品对象,客户商应使用不同的具体工厂

优点
便于交换系列产品,由于具体工厂类,在一个应用中只需要在初始化时出现一次,这使得改变一个应用的具体工厂变得很容易,它只要改变具体工厂即可使用不同的产品配置
它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体的工厂实现分离,不会出现在客户代码中

缺陷
1,添加新的表,要更改多个工厂类
2,程序中有多个地方使用了

IFactory factory = new AccessFactory();
1
现在换个数据库

IFactory factory = new SqlServerFactory();
1
你也要更改多个地方

总结:

简单工厂模式:管理对象类 调用接口

抽象工厂模式:接口实现类 调用接口

用简单工厂改进其缺陷
去除IFactory、SqlServerFactory和AccessFactory三个工厂类
使用DataAccess类取代它们

UML

代码
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 SqlserverUser();
         break;
         case "Access":
         result = new AccessUser();
         break;
     }
      return result;
}

public static IDepartment CreateDepartment()
{
      IDepartment result = null;
      switch (db)
     {
        case "SqlServer":
        result = new SqlserverDepartment();
        break;
        case "Access":
        result = new AccessDepartment();
        break;
     }
      return result;
   }
}
// test
User user = new User();
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser(1);

Department dept = new Department();
IDepartment id = DataAccess.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);

// result
在SQL Server中给User表增加一条记录
在SQL Server中根据ID得到User表一条记录
在SQL Server中给Department表增加一条记录
在SQL Server中根据ID得到Department表一条记录

这里使用了简单工厂的方法来解决了上面的缺陷,但同时又产生了新的问题(switch问题)
如果要新增Oracle数据库,抽象工厂本来只要增加一个OracleFactory工厂即可,这里简单工厂要修改switch增加case

.NET中的依赖注入( Dependency Injection)
using System.Reflection;

Assembly.Load("程序集名称").CreateInstance("命名空间.类的名称");

// 常规写法
IUser result = new SqlServerUser();

// 反射写法
using System.Reflection;

IUser result = (IUser)Assembly.Load("抽象工厂模式").CreateInstance("抽象工厂模式.SqlServerUser");

使用反射的具体代码

using System.Reflection;

class DataAccess
{
     private static readonly string AssemblyName = "PatternTest";

private static readonly string db = "AbstractPattern.Sqlserver";
     // private static readonly string db = "AbstractPattern.Access";

public static IUser CreateUser()
   {
      string className = AssemblyName + "." + db + "User";
      return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
   }

public static IDepartment CreateDepartment()
  {
       string className = AssemblyName + "." + db + "Department";
       return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
  }
}

上述代码同样得到了结果

如果我们增加了Oracle数据访问,相关的类的增加是不可避免的,不过这叫扩展,开闭原则告诉我们对于扩展开放,对于修改关闭
我们只要修改db字符串变量的值为

// private static readonly string db = "AbstractPattern.Oracle";
1
每次更换数据库时还是要修改程序修改db值重编译,如果可以不修改程序,才是真正的开放-封闭原则

解决方案:使用配置文件

C#设计模式之:抽象工厂模式与反射的更多相关文章

  1. 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)

    原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factor ...

  2. 桥接模式及C++实现 C++设计模式-AbstractFactory抽象工厂模式

    桥接模式及C++实现 桥接模式 先说说桥接模式的定义:将抽象化(Abstraction)与实现化(Implementation)分离,使得二者可以独立地变化. 桥接模式号称设计模式中最难理解的模式之一 ...

  3. Java 设计模式之抽象工厂模式(三)

    原文地址:Java 设计模式之抽象工厂模式(三) 博客地址:http://www.extlight.com 一.前言 上篇文章 <Java 设计模式之工厂模式(二)>,介绍了简单工厂模式和 ...

  4. 设计模式之抽象工厂模式(附带类似反射功能的实现/c++)

    问题描述 假设我们要开发一款游戏, 当然为了吸引更多的人玩, 游戏难度不能太大(让大家都没有信心了,估计游戏也就没有前途了),但是也不能太简单(没有挑战性也不符合玩家的心理).于是我们就可以采用这样一 ...

  5. 【设计模式】抽象工厂模式 Abstract Factory Pattern

    简单工厂模式是一个工厂类根据工厂方法的参数创建不出不同的产品, 工厂方法模式是每一个产品都有一个一一对应的工厂负责创建该产品.那么今天要讲的抽象工厂模式是一个工厂能够产生关联的一系列产品.抽象工厂模式 ...

  6. 抽象工厂模式(JAVA反射)

    实例代码(JAVA):模式动机     在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方 ...

  7. java设计模式之抽象工厂模式

    上一篇文章(http://www.cnblogs.com/liaoweipeng/p/5768197.html)讲了简单工厂模式,但是简单工厂模式存在一定的问题,如果想要拓展程序,必须对工厂类进行修改 ...

  8. 设计模式:抽象工厂模式(Abstract Factory)

    定   义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 结构图: 示例结构图: 实体类: class User { public int Id { get; set; } p ...

  9. php设计模式之抽象工厂模式

    之前总结了一下工厂模式,其实准确地说是简单 工厂模式,在它的基础上再进行抽象就可以得到一种新的模式:抽象工厂模式. 专业一点的定义为: 抽象工厂模式(Abstact Factory)是一种常见的软件设 ...

随机推荐

  1. wordpress 使用less 样式无法及时刷新

    wordpress 样式无法及时刷新 wordpress编写style样式时,无法及时刷新页面,因此特意记录一番如何处理较好,网友的建议清除Chrome缓存,实时修改style携带的参数 折腾之旅开启 ...

  2. 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)

      前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面.   奇葩 这两天遇到 ...

  3. 猎豹浏览器(chrome内核)屏蔽视频广告

    1.基于猎豹浏览器(原则上chrome内核浏览器都可以) 2.下载插件Adblock Plus,下载地址:http://chromecj.com/productivity/2014-07/24/dow ...

  4. POJ 2309 BST(树状数组Lowbit)

    题意是给你一个满二叉树,给一个数字,求以这个数为根的树中最大值和最小值. 理解树状数组中的lowbit的用法. 说这个之前我先说个叫lowbit的东西,lowbit(k)就是把k的二进制的高位1全部清 ...

  5. DevExpress v17.2新版亮点—WPF篇(五)

    用户界面套包DevExpress v17.2终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress WPF v17.2 新的Hamburger Menu.Sched ...

  6. Linux C 文件操作函数(~上善止水~)

    翻翻笔记,整理一下 C 语言中的文件操作函数 ~~~~~~,多注意细节,maybe 细节决定成败~ 1. fopen /* fopen(打开文件) * * 相关函数 open,fclose * * 表 ...

  7. python3:文件读写+with open as语句

    转载请表明出处:https://www.cnblogs.com/shapeL/p/9141238.html 前提:文中例子介绍test.json内容: hello 我们 326342 1.文件读取 ( ...

  8. HslControls组件库 工业控件库 曲线控件 时间控件 管道控件 温度计控件 阀门控件 传送带控件 进度条控件 电池控件 数码管控件等等

    本篇博客主要对 HslControls 组件做一个大概的总览介绍,更详细的内容可以参照页面里的子链接,还有github上的源代码,然后进行相关的学习,和使用. Prepare 先从nuget下载到组件 ...

  9. 微信小程序插件使用

    使用插件 小程序开发者可便捷地把插件添加到自己的小程序内,丰富小程序的服务.当用户在使用小程序时,将可以在小程序内使用插件提供的服务. 开放范围 所有小程序 接入流程 在小程序管理后台添加插件 小程序 ...

  10. 故障排查:vsftpd无法用浏览器访问

    在CentOS6上搭建的ftp服务器,突然无法使用浏览器进行访问,但使用xftp等工具可以正常访问 想到之前修改过阿里云的安全组设置,推测可能有关 1)修改vsftpd的配置,手动指定被动模式的随机连 ...