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

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. Linq的简介和基础知识学习

    学习LINQ之前,我们要知道LINQ是干什么,解决什么问题的,怎样学习? 一.LINQ简介 1.什么是LINQ? 什么是LINQ?LINQ中文翻译为语言集成查询(Language Integrated ...

  2. eclipse设置(颜色,字体等)

    1.设置jsp中js块的颜色: 选择Preferences菜单项.在弹出的窗口的左侧树形菜单依次选择:MyEclipse.Files and Editors.Javascript.Editor.Syn ...

  3. Oracle/MySQL decimal/int/number 转字符串

    有时客户需要流水数据,当导出为excel的时候,客户编号等很长数字的栏位,被excel变成科学记数法,无法正常查看. 因此,需要将Oracle/MySQL中的decimal/int 转 varchar ...

  4. Memcached 扩展常用方法

    保存数据 向memcached保存数据的方法有 add replace set 它们的使用方法都相同: $add = $memcached->add( '键', '值', '期限' ); $re ...

  5. CCF CSP 201703

    CCF CSP 2017·03 做了一段时间的CCF CSP试题,个人感觉是这样分布的 A.B题基本纯暴力可满分 B题留心数据范围 C题是个大模拟,留心即可 D题更倾向于图论?(个人做到的D题基本都是 ...

  6. L220

    He must not allow this unusual barrier (obstacle) to stop him from fighting against the enemy.他绝不能让这 ...

  7. ORACLE常用系统查询

    目录(?)[-] 查询系统所有对象 查看系统所有表 查看所有用户的表 查看当前用户表 查看用户表索引 查看主键 查看唯一性约束 查看外键 查看表的列属性 查看所有表空间 查看oracle最大连接数 修 ...

  8. ipAllocate_and_linkState_hacking

    #!/bin/bash # Author: Joshua Chen # Date: Jun # Location: Shenzhen #. 解读这两个程序是因为程序中包含了大部分shell脚本的基本语 ...

  9. tiny4412 UART for C printf Demo

    /************************************************************************** * tiny4412 UART for C pr ...

  10. requests中获取请求到文本编码格式

    1.使用requests模块: import requests 2.通过网络请求,并获取到数据 url = "http://www.stat-nba.com/award/item14.htm ...