抽象工厂模式 - 设计模式学习

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

  以下给出抽象工厂方法模式的UML图:

    

  回到《大话设计模式》里面的双数据库访问的例子:

namespace ConsoleApplication1
{
    class 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 Department
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _deptNmae
        {
            get { return _deptNmae; }
            set { _deptNmae = value; }
        }
    }

    //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
    interface IUser
    {
        void Insert(User user);
        User GetUser(int id);
    }

    class SqlserverUser : IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("Sql Server添加一条记录");
        }

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

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

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

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

    class SqlserverDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Sqlserver中给Department表插入一条记录");
        }

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

    class AccessDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Access中给Department表插入一条记录");
        }

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

    interface IFactory
    {
        IUser CreateUser();

        IDepartment CreateDepartment();
    }

    //SQLServer实例化工厂,负责实例化SqlserverUser和SqlserverDepartment
    class SqlServerFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new SqlserverUser();
        }

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

    //Access实例化工厂,负责实例化AccessUser和AccessDepartment
    class AccessFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new AccessUser();
        }

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

    class Program
    {
        static void Main(string[] args)
        {
            IFactory factory = new SqlServerFactory();

            IUser iu = factory.CreateUser();    //获得数据库User访问类的对象
            iu.Insert(new User());
            iu.GetUser(1);

            IDepartment idepartment = factory.CreateDepartment();   //获得数据库Department访问类的对象
            idepartment.Insert(new Department());
            idepartment.GetDepartment(1);

            Console.ReadKey();
        }
    }
}

  其实以上代码就叫做抽象工厂模式了,当只有一个User表的时候,就叫工厂方法模式。当有了多个表了,就叫抽象工厂模式。但是以上代码是非常不好的,为什么?例如当你还要增加一个Project表的时候,就需要增加三个类,IProject、SqlserverProject、AccessProject,同时还需要更改IFactory、SqlserverFactory、AccessFactory。增加一张表就要更改三个类,这个是比较悲剧的。

  因此,以下给出一个用简单工厂模式来优化抽象工厂模式的代码:

namespace ConsoleApplication1
{
    class 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 Department
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _deptNmae
        {
            get { return _deptNmae; }
            set { _deptNmae = value; }
        }
    }

    //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
    interface IUser
    {
        void Insert(User user);
        User GetUser(int id);
    }

    class SqlserverUser : IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("Sql Server添加一条记录");
        }

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

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

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

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

    class SqlserverDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Sqlserver中给Department表插入一条记录");
        }

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

    class AccessDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Access中给Department表插入一条记录");
        }

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

    class DataAccess
    {
        private static readonly string db = "SqlServer";    //事先就设置好的数据库
        //private static readonly string db = "Access";     //也就是说,更改数据库改的是这里了 

        public static IUser CreateUser()    //这是第一个User的简单工厂
        {
            IUser result = null;
            switch (db)         //根据db的设置实例化不同的User数据库访问对象
            {
                case "SqlServer":
                    result = new SqlserverUser();
                    break;
                case "Access":
                    result = new AccessUser();
                    break;
            }
            return result;
        }

        public static IDepartment CreateDepartment()    //这是Department的简单工厂
        {
            IDepartment result = null;
            switch (db)
            {
                case "Sqlserver":
                    result = new SqlserverDepartment();
                    break;
                case "Access":
                    result = new AccessDepartment();
                    break;
            }
            return result;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IUser iu = DataAccess.CreateUser();    //获得数据库User访问类的对象,要改数据库就要改DataAccess里面的设置
            iu.Insert(new User());
            iu.GetUser(1);

            IDepartment idepartment = DataAccess.CreateDepartment();   //获得数据库Department访问类的对象,这里没有依赖SqlserverFactory或AccessFactory了
            idepartment.Insert(new Department());
            idepartment.GetDepartment(1);

            Console.ReadKey();
        }
    }
}

  经过简单工厂模式优化之后,客户端就不再依赖于SqlserverFactory或AccessFactory了,带到了解耦的目的。如果要添加一个Project,只需要添加响应类,但改就只需要修改DataAccess就可以了(在DataAccess里面在添加一个简单工厂)。很明显者不是最终方案,因为简单工厂方法还是要修改,switch case。

  以下还有通过反射实现的更加好的方案:

namespace ConsoleApplication1
{
    class 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 Department
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _deptNmae
        {
            get { return _deptNmae; }
            set { _deptNmae = value; }
        }
    }

    //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
    interface IUser
    {
        void Insert(User user);
        User GetUser(int id);
    }

    class SqlserverUser : IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("Sql Server添加一条记录");
        }

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

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

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

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

    class SqlserverDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Sqlserver中给Department表插入一条记录");
        }

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

    class AccessDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Access中给Department表插入一条记录");
        }

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

    class DataAccess
    {
        private static readonly string AssemblyName = "ConsoleApplication1";    //字符串为程序集的名字
        private static readonly string db = ConfigurationManager.AppSettings["DB"];

        public static IUser CreateUser()
        {
            string className = AssemblyName + "." + db +"User"; //拼接SqlserverUser类或AccessUser类所在的位置
            return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);    //反射创建实例
        }

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

    class Program
    {
        static void Main(string[] args)
        {
            IUser iu = DataAccess.CreateUser();    //获得数据库User访问类的对象,要改数据库就要改DataAccess里面的设置
            iu.Insert(new User());
            iu.GetUser(1);

            IDepartment idepartment = DataAccess.CreateDepartment();   //获得数据库Department访问类的对象
            idepartment.Insert(new Department());
            idepartment.GetDepartment(1);

            Console.ReadKey();
        }
    }
}

  配置文件App.config代码:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DB" value="Access" />
  </appSettings>
</configuration>

  以上就是反射+抽象工厂的方法, 还是非常强大的,强大到什么程度呢?例如上面的代码,要修改数据库访问对象例如将Sqlserver改为Access根本不需要改动程序重新编译,只需要改动App.config就可以了。其实这里的反射只是改进了简单工厂模式而已,与抽象工厂没太大的关系。要记住,所有在用到简单工厂的地方都可以考虑用反射技术来去除switch解除分支判断所带来的耦合。

  在以上的代码中,要增加一个Project表的话,只需要添加三个Project相关的类(扩展),再修改DataAccess,在其中增加一个CreateProject()方法就可以了。

时间: 2024-10-07 10:56:59

抽象工厂模式 - 设计模式学习的相关文章

简单工厂模式、工厂方法模式和抽象工厂模式-设计模式学习

1.简单工厂模式 简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例.简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现. 工厂(Creator)角色 简单工厂模式的核心,它负责实现创建所有实例的内部逻辑.工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象. 抽象产品(Product)角色 简单工厂模式所创建的所有

工厂模式&amp;抽象工厂——HeadFirst设计模式学习笔记

当使用new实例化一个类时,使用的是实现,而不是接口,代码捆绑着具体类会导致代码更脆弱缺乏弹性,使用松耦合的OO模式可以得到解脱. 工厂:封装对象的创建,处理创建对象的细节 静态工厂:利用静态方法定义一个简单的工厂.优点:不需要创建工厂类的实例化.缺点:不能通过继承改变创建方法行为. 简单工厂:简单工厂并不是一种设计模式,因为只是简单的把创建对象的代码封装起来 工厂模式:在父类定义了一个创建对象的接口,通过让子类决定创建的对象是什么,来达到让对象创建的过程封装的目的.工厂方法让类把实例化推迟到子

设计模式学习03—抽象工厂模式

1.动机与定义 工厂模式中,一个工厂仅仅能提供一个或一类产品,当产品种类较多,形成产品系列(比方我们要创建跨平台的button,菜单,文本框等等一系列GUI控件: 单纯使用工厂模式会产生大量工厂,并且后期维护也不方便,我们能够从产品中找到规律,假设产品等级相对固定,以后仅仅会新增产品族,那么我们就能够把整个产品族放到一个工厂创建,以后新增其它系统产品族也很方便,例如以下图: 这样的模式就是抽象工厂,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能

设计模式——抽象工厂模式学习

要想正确的理解设计模式,首先必须明确它是为了解决什么问题而提出来的. 抽象工厂设计模式概念: 针对抽象工厂这个设计模式,我查找了不少资料,感觉只有涉及产品级别和产品族的才是理解了抽象工厂设计模式的精髓,工厂方法模式针对的是一个产品等级结构:而抽象工厂模式针对的是多个产品等级结构.有些观点认为抽象工厂模式是为了解决客户端代码与工厂类的耦合问题,我认为这种观点的解决方案只是简单工厂模式的一个应用,而这种观点认为的抽象工厂模式是: 工厂模式+简单工厂模式=抽象工厂模式,这是不正确. 针对的问题: 针对

设计模式学习(二)——简单工厂模式、工厂模式、抽象工厂模式

最近抽时间将之前看过的"程序人生"公众号推送的一篇工厂模式的介绍进行了实践,为了加深自己理解,特将自己的学习理解记录于此.初识设计模式,就被设计模式的精妙深深吸引,感觉脱离设计模式的代码就失去了美丽.作为一个测试,平日写代码的机会肯定不如开发多,但是希望自己能通过努力逐步提升代码水平,有一天也能写出优美的代码.如果有对于工厂模式或其他设计模式感兴趣的朋友欢迎一起探讨. 一.简单工厂模式 定义:专门定义一个类用来创建其他类的实例,被创建的实例通常具有共同的父类. 场景一:恰巧今天,老大兴

Java研究之学习设计模式-抽象工厂模式详解

 简介:          当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产[1] 品角色都有两个具体产品.抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化.每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例. 每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构:而抽象工厂模式针对的是多个产品等级结构.(摘自百度百科) 话语说得太抽象,程序员最好的表示方式

java/android 设计模式学习笔记(4)---抽象工厂模式

再来介绍一下抽象工厂模式(Abstact Factory Pattern),也是创建型模式之一,上篇博客主要介绍了工厂方法模式.抽象工厂模式和工厂方法模式稍有区别.工厂方法模式中工厂类生产出来的产品都是具体的,也就是说每个工厂都会生产某一种具体的产品,但是如果工厂类中所生产出来的产品是多种多样的,工厂方法模式也就不再适用了,就要使用抽象工厂模式了. 抽象工厂模式的起源或者最早的应用,是对不同操作系统的图形化解决方案,比如在不同操作系统中的按钮和文字框的不同处理,展示效果也不一样,对于每一个操作系

设计模式学习-抽象工厂模式

1.定义 提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类. 2.类图 3.代码示例 1 package com.zhaoyangwoo.abstractfactory; 2 3 /** 4 * Created by john on 16/5/2. 5 * @author wuzhaoyang 6 * <p> 7 * 抽象工厂:多个抽象产品类,派生出多个具体产品类:一个抽象工厂类,派生出多个具体工厂类:每个具体工厂类可创建多个具体产品类的实例. 8 * 即提供一个创建一系列相关或

《Head First 设计模式》学习笔记——工厂模式 + 抽象工厂模式

设计模式 工厂模式:定义一个创建对象的接口,但由子类决定要实例化的是哪一个.工厂方法让类把实例化推迟到子类. 所谓的"决定",并非指模式同意子类本身在执行时做决定,而是指在编写创建者类时.不须要知道实际创建的产品是哪一个. 选择了使用这个子类,就自然的决定了实际创建的产品是什么. 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族.而不须要指定详细类. 抽象工厂的任务时定义一个负责创建一组产品的接口.这个接口内的每一个产品都负责创建一个详细产品.使用工厂方法. 设计原则 (1)多