抽象工厂模式——选择产品族实现

问题导入

一个项目实现后可能给不同的客户使用,每个客户使用的数据库不同,在项目实现过程中就要考虑到如何满足不同客户不同数据库类型的需求(包括客户添加表的需求)。
没有考虑到换数据库的数据库访问实例

class User//数据库内的User表
{
    
    
 private int _id;
 public int ID
 {
    
    
  get{
    
    return _id;}
  set{
    
    _id=value}
  private string _name;
  public string Name
  {
    
    
   get{
    
    return_name;}
   set{
    
    _name=value;}
  }
}
class SqlserverUser//操作Sqlserver中User表的方法
{
    
    
 public void Insert(User user)
 {
    
    
  Console.WriteLine("在Sqlserver中给User表增加一条记录");
 }
 public User GetUser(int id)
 {
    
    
  Console.WriteLine("在Sqlserver中根据id得到一条记录");
  return null;
 }
}
class Program
{
    
    
 static void Main(string[] args)
 {
    
    
  User user=new User();
  SqlserverUser su=new Sqlserveruser();
  su.Insert(User);
  su.GetUser(1);
  Console.Read();
 }
}

缺点:su对象被限定在Sqlserver框架上,耦合性很强,后期更换数据库不方便。

问题解决

用工厂方法模式初步解耦合

在这里插入图片描述
IUSer接口,解除与具体数据库访问的耦合

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

SqlserverUser继承IUser用户表访问接口,访问User

class SqlserverUser:IUser
{
    
    
 public void Insert(User user)
 {
    
    
  Console.WriteLine("在Sqlserver中给User表增加一条记录");
 }
 public User GetUser(int id)
 {
    
    
  Console.WriteLine("在Sqlserver中根据id得到一条记录");
  return null;
 }
}

AccessUser继承IUser用户表访问接口,访问User

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

定义一个创建访问User表对象的工厂接口,解除与具体数据库工厂耦合

interface IFactory
{
    
    
 Iuser CreateUser();
}

创建生成SqlserverUser的SqlserverFactory(实例化工厂接口)

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

创建生成AccessUser的AccessFactory(实例化工厂接口)

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

客户端代码

class Program
{
    
    
 static void Main(string[] args)
 {
    
    
  User user=new User();
  IFactory factory=new SqlserveruserFactory();
  IUser iu=factory.CreateUser();
  iu.Insert(User);
  iu.GetUser(1);
  Console.Read();
 }
}

这样就解决了与具体操作类的耦合,与具体构造操作类的工厂的耦合

再增加访问Department表引发了什么思考?

抽象工厂模式
这是抽象工厂模式实现问题UML图,工厂方法模式与抽象工厂模式有什么不同呢?为何增加了一个表就变成了抽象工厂方法?先看看工厂方法模式的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。可以理解为它关注的一个类(一个产品),本例就是一种User操作类的Sql和Access两种实例,使得再增加Qracle操作User类能符合开放封闭原则;抽象工厂模式定义:提供一个创建一系列相关或相互依赖的接口,而无须指定它们具体的类;二者相比:工厂方法适用一个类(一个产品)延时到子类实现,抽象工厂适用一系列类(一系列产品)延迟到子类实现。抽象工厂在多产品的情况下能很好的体现这些产品及其具体实现的逻辑关系,抽象工厂本质是选择产品族的实现
产品族和等级结构
产品族与产品等级结构示意图

扫描二维码关注公众号,回复: 12718950 查看本文章
冰箱的等级结构 空调的等级结构 电视的等级结构
小米的产品族 小米冰箱 小米空调 小米电视
海尔的产品族 海尔冰箱 海尔空调 海尔电视
格力的产品族 格力冰箱 格力空调 格力电视

在这里插入图片描述

现在豁然开朗了吧,我们好好絮叨絮叨抽象工厂模式

在这里插入图片描述
抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的
具体工厂角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的
抽象产品角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同用有的接口
具体产品角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。

什么情形下使用抽象工厂模式?

  • 希望一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节时
  • 一个系统有多于一个的产品族,而系统只消费其中的某一产品族

从“开放-封闭”原则谈优缺点

“开放—封闭”原则要求系统对扩展开放,对修改封闭。通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增加包括两个方面:

  • 增加产品族:抽象工厂模式很好的支持了“开放-封闭”原则
    在这里插入图片描述
  • 增加新产品的等级结构:需要修改所有的工厂角色,没有很好支持“开放-封闭”原则。
    在这里插入图片描述

综合起来,**抽象工厂模式以一种倾斜的方式支持增加新的产品,**它为新的产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。
本质:选择产品族的实现

用简单工厂进一步改进抽象工厂

在这里插入图片描述
DataAccess

    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":
                   return =new SqlserverUser();
                   break;
              case "Access":
                   return =new AccessUser();
                   break;
            }            
        }
        public static IDepartment CreateDepartment()
        {
    
    
            IDepartment result=null;
            Switch(db)
            {
    
    
              case "Sqlserver":
                   return =new SqlserverDepartment();
                   break;
              case "Access":
                   return =new AccessDepartment();
                   break;
            }
        }
    }

客户端

static void Main(string[] args)
{
    
    
 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);
Console.Read();
}

客户端中没有出现任何一个SQlServer或Access的字样,达到了解耦合的目的。

看到这可能又要问了,还是要拆开DataAccess去修改db的值,很麻烦,用反射加配置文件就能很好解决这个问题。Java用反射+配置文件结合抽象工厂模式实现数据库访问程序

猜你喜欢

转载自blog.csdn.net/qq_43515378/article/details/106112850