C#设计模式(1)——简单工厂模式

2021-06-30 13:05

阅读:382

标签:use   工作量   code   def   new   设计   形式   不可   运行程序   

1.什么是简单工厂

  现实中的工厂负责生产产品,编程中的简单工厂顾名思义就是一个生产对象的类,它的主要作用是封装改变。我们在平时的工作必不可免的和各种数据库打交道,我们就以一个数据库服务类为例来分析简单工厂的作用。代码如下:

用户类:

    // 用户类
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

数据库服务抽象类(DbUserService),主要对用户进行添加和删除,类中有两个抽象方法,AddUser()和RemoveUser():

   //数据库服务抽象类
    public abstract class DbUserService
    {
        public abstract void AddUser();//添加用户
        public abstract void RemoveUser();//获取用户
    }

数据库服务具体类(SqlserverUserService和MysqlUserService),实现类对用户进行添加和删除的具体操作:

    //Sqlserver中对用户进行添加和删除
    public class SqlserverUserService:DbUserService
    {
        public override void AddUser()
        {
            Console.WriteLine("sqlserver 添加一个用户");
        }

        public override void RemoveUser()
        {
            Console.WriteLine("sqlserver 删除一个用户");
        }
    }

    //mysql中对用户添加和删除
    public class MysqlUserService : DbUserService
    {
        public override void AddUser()
        {
            Console.WriteLine("Mysql 添加一个用户");
        }

        public override void RemoveUser()
        {
            Console.WriteLine("Mysql 删除一个用户");
        }
    }

客户端代码:

    class Program
    {
        static void Main(string[] args)
        {
            //我们的软件中用了很多new来获取SqlserverUserService的实例
            DbUserService userService1 = new SqlserverUserService();
            DbUserService userService2 = new SqlserverUserService();
            DbUserService userService3 = new SqlserverUserService();
            DbUserService userService4 = new SqlserverUserService();
            DbUserService userService5 = new SqlserverUserService();
            userService1.AddUser();
            userService1.RemoveUser();
            Console.ReadKey();
        }
    }

运行程序结果如下:

技术分享图片

  我们可以看到程序运行没有问题,通过new一个sqlserverUserService服务类实例可以成功地添加和删除用户,但是如果我们想把数据库切换到Mysql怎么去做呢?最简单直接的方法就是把 new SqlserverUserService 全部替换成 new MysqlUserService 。如果我们的软件中new了100个SqlserverUserService实例呢?一个一个地去替换会是一个巨大的工作量,同时通过new的方式来创建SqlserverUserService的实例,会让DbUserService和客户端产生强耦合关系,这时候使用简单工厂就可以帮助我们降低耦合,减少工作量了。添加一个DbUserServiceFactory,这个工厂类专门来创建DbUserService的实例:

  //数据库服务工厂
    public class DbUserServiceFactory
    {
        public static DbUserService Create(string dbname)
        {
            DbUserService dbUserService = null;
            switch (dbname)
            {
                case "sqlserver":
                    dbUserService = new SqlserverUserService();
                    break;
                case "mysql":
                    dbUserService = new MysqlUserService();
                    break;
                default:
                    break;
            }
            return dbUserService;
        }
    }

客户端的代码就可以改成:

    class Program
    {
        static void Main(string[] args)
        {
            //我们的软件中用了很多new来获取SqlserverUserService的实例
            DbUserService userService1 = DbUserServiceFactory.Create("sqlserver");
            DbUserService userService2 = DbUserServiceFactory.Create("sqlserver");
            DbUserService userService3 = DbUserServiceFactory.Create("sqlserver");
            DbUserService userService4 = DbUserServiceFactory.Create("sqlserver");
            DbUserService userService5 = DbUserServiceFactory.Create("sqlserver");
            userService1.AddUser();
            userService1.RemoveUser();
            Console.ReadKey();
        }
    }

  运行程序结果一样的,这样做有什么好处呢?我们看到我们把以前的 new SqlserverUserService() 替换成了  DbUserServiceFactory.Create("sqlserver") ,客户端和SqlserverUserService的耦合变成了 客户端DbUserServiceFactorySqlserverUserService 形式,有效降低了客户端和数据库服务实现类的耦合。我们还用一个疑问,程序改成这样的话,如果我们想从SqlServer切换到Mysql就要把DbUserServiceFatroy.Create("sqlserver")中的sqlserver字符串全部替换成mysql字符串,不是还要改100次?任务量没有降低呀!对于这个问题,我们可以把dbname存放在一个地方,如配置文件中,这样我们想切换数据库就直接修改配置文件即可,如下:

配置文件:

  appSettings>
    add key="dbname" value="sqlserver"/>
  appSettings>

工厂类修改为:

    //数据库服务工厂
    public class DbUserServiceFactory
    {
        private static readonly string dbname = ConfigurationManager.AppSettings["dbname"];
        public static DbUserService Create()
        {
            DbUserService dbUserService = null;
            switch (dbname)
            {
                case "sqlserver":
                    dbUserService = new SqlserverUserService();
                    break;
                case "mysql":
                    dbUserService = new MysqlUserService();
                    break;
                default:
                    break;
            }
            return dbUserService;
        }
    }

客户端代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            DbUserService userService1 = DbUserServiceFactory.Create();
            DbUserService userService2 = DbUserServiceFactory.Create();
            DbUserService userService3 = DbUserServiceFactory.Create();
            DbUserService userService4 = DbUserServiceFactory.Create();
            DbUserService userService5 = DbUserServiceFactory.Create();
            userService1.AddUser();
            userService1.RemoveUser();
            Console.ReadKey();
        }
    }

现在我们想把数据库服务切换到mysql,只需要将配置文件中的sqlserver改成mysql即可,修改配置文件后运行结果如下:

技术分享图片

大功告成!这时有一个问题,如果我们想添加一个mongodb服务怎么办呢?除了添加一个MongodbUserService类,还要在UserServiceFactory类中添加一段case 代码。按照开闭原则,添加一个实现类没什么问题,开闭原则中对添加开发;但是修改简单工厂类就违背了对修改闭合的原则了。后边的工厂模式就是专门用来解决这个问题的。

2.小结

上边例子的类图:

技术分享图片

简单工厂的优点:

  1.简单工厂可以有效地降低客户端和具体对象的耦合,将new具体对象的任务交给了一个简单工厂类

  2可以有效的进行代码复用,如客户端A和客户端B都需要一个具体对象,客户端A和客户端B都可以通过同一个简单工厂来获取具体类型的实例

简单工厂的缺点:

  一定程度上违背了开闭原则,在新增产品时需要修改简单工厂类

 

C#设计模式(1)——简单工厂模式

标签:use   工作量   code   def   new   设计   形式   不可   运行程序   

原文地址:https://www.cnblogs.com/wyy1234/p/9978389.html


评论


亲,登录后才可以留言!