设计模式之工厂类模式总结对比、简单工厂模式、工厂方法模式、抽象工厂模式、带反射的工厂模式、例子代码分析、最详细

本文详细介绍了工厂模式的几种形式,包括简单工厂模式、工厂方法模式、抽象工厂模式,以及如何通过反射技术进一步优化工厂模式。通过一系列的例子,展示了如何在数据库操作中应用这些模式,以实现对不同数据库如SqlServer、MySql的Users和Departments表的灵活切换。文章最后提供了所有源码的GitHub链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 题目

假设某公司同时用SqlServer、MySql数据库,即会切换两数据库(不同数据库的sql语句有些许差异),同时,两数据库里均有对Users、Departments表的操作(sql代码不一样),用工厂类的方法来编写程序

因为设计模式有差异,所以不同工厂模式的题目会有些不同,总体一样,细节有些不同

需要知道的是,我们把需求当做产品类,也就是User表和Department表

2. 简单工厂模式

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users的表,现通过简单工厂模式来让用户选择使用哪个数据库的Users表

  1. 定义抽象数据库类
//定义抽象数据库类
    abstract class DatabaseUser
    {
        public abstract void Use();
        public abstract void Insert();
    }
  1. 实现抽象数据库类
 class SqlServerUser : DatabaseUser
    {
        public override void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public override void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : DatabaseUser
    {
        public override void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public override void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }
  1. 定义简单工厂类
class Factory
    {
        public DatabaseUser GetDatabase(string databaseName)
        {
            DatabaseUser database = null;
            switch (databaseName)
            {
                case "SqlServer":
                    database = new SqlServerUser();
                    break;
                case "MySql":
                    database = new MySqlUser();
                    break;
            }
            return database;
        }
    }
  1. 客户端
 class Program
    {
        //简单工厂模式的好处是方便,但是其违反了开放封闭原则,每次要加数据库就需要更改工厂类的分支语句
        static void Main(string[] args)
        {
            Factory factory = new Factory();
            var db1 = factory.GetDatabase("SqlServer");
            db1.Insert();
            db1.Use();

            var db2 = factory.GetDatabase("MySql");
            db2.Insert();
            db2.Use();

            Console.Read();
        }
    }

总结:
简单工厂模式的好处是很方便的利用工厂进行对象的创建,但是其违反了开放封闭原则,原因是每次要加数据库(比如公司又要使用Oracle数据库)就需要更改工厂类的分支语句

我们发现,为了把工厂类中的分支去掉,其实可以把一个一个分支都拿出来,单独拿不同的工厂创建,这个思路其实就是工厂方法模式

3. 工厂方法模式

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users的表,现通过工厂方法模式来让用户选择使用哪个数据库的Users表

结构图(结构是这样,里面函数名称可能不一致):
在这里插入图片描述

代码:

  1. 建立数据库表类的接口
interface IUsers
    {
        public void Insert();
        public void Use();
    }
  1. 继承其接口的具体类
class SqlServerUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }
  1. 建立工厂接口
interface IFactory
    {
        public IUsers GetUsers();
    }
  1. 继承工厂接口的具体工厂,生产具体的工厂
 class SqlServerUserFactory : IFactory
    {
        public IUsers GetUsers()
        {
            return new SqlServerUser();
        }
    }
    class MySqlUserFactory : IFactory
    {
        public IUsers GetUsers()
        {
            return new MySqlUser();
        }
    }
  1. 客户端调用
 class Program
    {
        //工厂方法模式是简单工厂模式的升级版,它实现了开放封闭原则,每次需要添加具体时候,比如添加Oracle数据库,先增加一个具体的OracleUsers产品类,然后增加一个生产该类的具体工厂
        static void Main(string[] args)
        {
            //SqlServer的User表的使用
            IFactory factory = new SqlServerUserFactory();
            var db1 = factory.GetUsers();
            db1.Insert();
            db1.Use();

            //MySql的User表的使用
            IFactory factory1 = new MySqlUserFactory();
            var db2 = factory1.GetUsers();
            db2.Insert();
            db2.Use();

            Console.Read();
        }
    }

总结:
工厂方法模式是简单工厂模式的升级版,它实现了开放封闭原则,每次需要添加具体产品类的时候,比如添加Oracle数据库,先增加一个具体的OracleUsers产品类,然后增加一个生产该类的具体工厂

这是单一产品,即Users的表,如果还需要Departments的表,那我们就要有两个不同的产品接口了,此时,就是抽象工厂模式,抽象工厂模式和工厂方法模式不同的是前者是两个或者多个产品接口,而后者只有一个产品接口类

4. 抽象工厂模式

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users以及一张Departments的表,现通过抽象工厂模式来让用户选择使用哪个数据库的Users表或者Departments表

结构图(结构是这样,里面函数名称可能不一致):
在这里插入图片描述
代码:

  1. 建立Users数据库表类的接口
interface IUsers
    {
        public void Insert();
        public void Use();
    }
  1. 建立Departments数据库表类的接口
interface IDepartments
    {
        public void Insert();
        public void Use();
    }
  1. 继承其接口的具体类
class SqlServerUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }

    class SqlServerDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Departments表");
        }
    }
    class MySqlDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Departments表");
        }
    }
  1. 建立工厂接口
interface IFactory
    {
        public IUsers GetUsers();
        public IDepartments GetDepartments();
    }
  1. 继承工厂接口的具体工厂,生产具体的工厂
class SqlServerFactory : IFactory
    {
        public IUsers GetUsers()
        {
            return new SqlServerUser();
        }
        public IDepartments GetDepartments()
        {
            return new SqlServerDepartment();
        }
    }
    class MySqlFactory : IFactory
    {
        public IUsers GetUsers()
        {
            return new MySqlUser();
        }
        public IDepartments GetDepartments()
        {
            return new MySqlDepartment();
        }
    }
  1. 客户端
class Program
    {
        //抽象工厂模式其实就是工厂方法模式的升级版,工厂方法模式只有某个单独的产品类,一个产品接口;而抽象工厂模式包含了多个产品接口,有多个产品类,一定程度上符合了开放封闭原则;但是要添加会显得麻烦,比方添加一个新的产品类,要增加其产品接口以及继承者,还要修改工厂接口以及具体的工厂,太过于麻烦
        static void Main(string[] args)
        {
            IFactory factory = new SqlServerFactory();
            var db1 = factory.GetDepartments();
            db1.Insert();
            db1.Use();

            var db2 = factory.GetUsers();
            db2.Insert();
            db2.Use();

            IFactory factory1 = new MySqlFactory();
            var db3 = factory1.GetDepartments();
            db3.Insert();
            db3.Use();

            var db4 = factory1.GetUsers();
            db4.Insert();
            db4.Use();

            Console.Read();
        }
    }

总结:
抽象工厂模式其实就是工厂方法模式的升级版,工厂方法模式只有某个单独的产品类,一个产品接口;而抽象工厂模式包含了多个产品接口,有多个产品类,一定程度上符合了开放封闭原则;但是要添加会显得麻烦,比方添加一个新的产品类,要增加其产品接口以及继承者,还要修改工厂接口以及具体的工厂,太过于麻烦,我们发现简单工厂模式比较简单,我们用简单工厂模式来改造下抽象工厂模式

5. 简单工厂模式来改造抽象工厂模式

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users以及一张Departments的表,现通过简单工厂模式来改造抽象工厂模式让用户选择使用哪个数据库的Users表或者Departments表

结构图(结构是这样,里面函数名称可能不一致):
在这里插入图片描述
代码:

  1. 建立Users数据库表类的接口
interface IUsers
    {
        public void Insert();
        public void Use();
    }
  1. 建立Departments数据库表类的接口
interface IDepartments
    {
        public void Insert();
        public void Use();
    }
  1. 继承其接口的具体类
class SqlServerUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }

    class SqlServerDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Departments表");
        }
    }
    class MySqlDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Departments表");
        }
    }
  1. 定义简单工厂类
class Factory
    {
        public IUsers GetUsers(string db)
        {
            IUsers users = null;
            switch (db)
            {
                case "SqlServer":
                    users = new SqlServerUser();
                    break;
                case "MySql":
                    users = new MySqlUser();
                    break;
            }
            return users;
        }

        public IDepartments GetDepartments(string db)
        {
            IDepartments departments = null;
            switch (db)
            {
                case "SqlServer":
                    departments = new SqlServerDepartment();
                    break;
                case "MySql":
                    departments = new MySqlDepartment();
                    break;
            }
            return departments;
        }
    }
  1. 客户端
class Program
    {
        //这个用简单工厂模式改造抽象工厂模式的好处是,增加起来不用那么麻烦,但是仍然违反了开放封闭原则,我们应该想办法让简单工厂类里的分支语句消失,只要增加类,工厂也能检测到,那么就是靠反射来实现了
        static void Main(string[] args)
        {
            Factory factory = new Factory();
            var t = factory.GetDepartments("SqlServer");
            t.Insert();
            t.Use();

            Console.Read();
        }
    }

总结:
这个用简单工厂模式改造抽象工厂模式的好处是,增加起来不用那么麻烦,但是仍然违反了开放封闭原则,我们应该想办法让简单工厂类里的分支语句消失,只要增加类,工厂也能检测到,那么就是靠反射来实现了

6. 通过反射继续改善工厂模式

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users以及一张Departments的表,现通过运用反射技术来改造工厂模式让用户选择使用哪个数据库的Users表或者Departments表

结构图(结构是这样,里面函数名称可能不一致):
在这里插入图片描述
代码:

  1. 建立Users数据库表类的接口
interface IUsers
    {
        public void Insert();
        public void Use();
    }
  1. 建立Departments数据库表类的接口
interface IDepartments
    {
        public void Insert();
        public void Use();
    }
  1. 继承其接口的具体类
class SqlServerUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }

    class SqlServerDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Departments表");
        }
    }
    class MySqlDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Departments表");
        }
    }
  1. 简单工厂类里运用反射技术
 class Factory
    {
        public string table;
        public IUsers GetUsers()
        {
            var t =(IUsers) Assembly.Load("通过反射继续改善工厂模式").CreateInstance("通过反射继续改善工厂模式." + table);
            return t;
        }

        public IDepartments GetDepartments()
        {
            var t = (IDepartments)Assembly.Load("通过反射继续改善工厂模式").CreateInstance("通过反射继续改善工厂模式." + table);
            return t;
        }
    }
  1. 客户端
class Program
    {
        //通过反射改造的工厂,获取实例时候已经取消了分支判断语句,而是以反射的形式动态的根据需要创建实例,但是目前有个缺陷是,需要在客户端指定类名,当我们添加了新的产品类时候,还是需要更改客户端,我们可以更完美些;考虑写在配置文件里,不在客户端内传值
        static void Main(string[] args)
        {
            Factory factory = new Factory();
            factory.table = "SqlServerUser";
            var db=factory.GetUsers();
            db.Insert();
            db.Use();

            factory.table = "MySqlDepartment";
            var db1 = factory.GetDepartments();
            db1.Insert();
            db1.Use();

            Console.Read();
        }
    }

总结:
通过反射改造的工厂,获取实例时候已经取消了分支判断语句,而是以反射的形式动态的根据需要创建实例,但是目前有个缺陷是,需要在客户端指定类名,当我们添加了新的产品类时候,还是需要更改客户端,我们可以更完美些;考虑写在配置文件里,不在客户端内传值

7. 通过反射改善工厂模式最终版

题目:
现有两个数据库,一个SqlServer,一个MySql,并且两个数据库都有一张Users以及一张Departments的表,现通过运用反射技术来改造工厂模式让用户选择使用哪个数据库的Users表或者Departments表

代码:

  1. 建立Users数据库表类的接口
interface IUsers
    {
        public void Insert();
        public void Use();
    }
  1. 建立Departments数据库表类的接口
interface IDepartments
    {
        public void Insert();
        public void Use();
    }
  1. 继承其接口的具体类
class SqlServerUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Users表");
        }
    }
    class MySqlUser : IUsers
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Users表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Users表");
        }
    }

    class SqlServerDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("SqlServer为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("SqlServer使用Departments表");
        }
    }
    class MySqlDepartment : IDepartments
    {
        public void Insert()
        {
            Console.WriteLine("MySql为Departments表插入数据");
        }

        public void Use()
        {
            Console.WriteLine("MySql使用Departments表");
        }
    }
  1. 简单工厂类里运用反射技术
 class Factory
    {
        private string table = ConfigurationManager.AppSettings["db"];

        public IUsers GetUsers()
        {
            string t = table + "User";
            var w = (IUsers)Assembly.Load("通过反射改善工厂模式最终版").CreateInstance("通过反射改善工厂模式最终版." + t);
            return w;
        }

        public IDepartments GetDepartments()
        {
            string t = table + "Department";
            var w = (IDepartments)Assembly.Load("通过反射改善工厂模式最终版").CreateInstance("通过反射改善工厂模式最终版." + t);
            return w;
        }
    }
  1. 客户端
class Program
    {
        //通过反射改造的工厂,获取实例时候已经取消了分支判断语句,而是以反射的形式动态的根据需要创建实例,将选择实例化的字段写在配置文件里,不在客户端内传值,最终完美版
        //此时如果需要切换数据库只需要更改配置文件中的键值对<key-value>的value即可
        static void Main(string[] args)
        {
            Factory factory = new Factory();
            var db = factory.GetUsers();
            db.Insert();
            db.Use();


            var db1 = factory.GetDepartments();
            db1.Insert();
            db1.Use();

            Console.Read();
        }
    }
  1. 配置文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<appSettings>
		<add key="Db" value="SqlServer"/>
	</appSettings>
</configuration>

总结:
通过反射改造的工厂,获取实例时候已经取消了分支判断语句,而是以反射的形式动态的根据需要创建实例,将选择实例化的字段写在配置文件里,不在客户端内传值,最终完美版

此时如果需要切换数据库只需要更改配置文件中的键值对 key-value的value即可

8. 例子用的所有源码

https://github.com/516886731/-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值