小白设计模式入门(2)——简单工厂模式

一、简介

什么是简单工厂模式?

在现实生活中,工厂是负责生产产品的。在设计模式中,可以简单类比为:简单工厂模式负责生产对象的一个类。

我们平常编程中,当使用”new”关键字创建一个对象时,此时该类就依赖与这个对象,也就是他们之间的耦合度高,当需求变化时,我们就不得不去修改此类的源码。如果需求变化不多,项目开发人员不多,项目较小,那么这样的修改是可行的,但是当修改的代价较大时,应该尽量避免这种修改,并且能获得更好的兼容性。

此时我们可以运用面向对象(OO)的很重要的原则去解决这一的问题,该原则就是——封装改变。既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封装。这样的一种思路也就是我们简单工厂模式的实现方式了。

二、示例

这里给出一个是否使用简单工厂的区别代码示例,示例也可以在我的GitHub中看到

2.1 工厂类定义

GPS和IMU这两个类是最简单的类了。

加上抽象出的接口IEquip,以及简单工厂类EquipSimpleFactory,就构成了一个简单工厂模式下的类定义。
不用接口IEquip也行,不过那样在调用方法对具体产品进行处理时,需要对每个产品都写一个函数。

    public interface IEquip
    {
        string GetName();
    }

    public class EquipSimpleFactory
    {
        private static IEquip factory = null;

        public static IEquip CreateFactory(string name)
        {
            switch (name)
            {
                case "gps":
                    factory = new Gps();
                    break;
                case "imu":
                    factory = new IMU();
                    break;
                default:
                    throw new NotImplementedException();
            }
            return factory;
        }
    }

    public class Gps : IEquip
    {
        public string GetName()
        {
            return nameof(Gps);
        }
    }

    public class IMU : IEquip
    {
        public string GetName()
        {
            return nameof(IMU);
        }
    }

2.2 不使用设计模式的调用

如果不使用设计模式,那么如果要调用其中一个类,可能的写法如下所示。可以看到,每个不同的类,都需要做判断。如果需要修改,每个部分都是独立的,需要逐一修改,比较麻烦。

        private void button2_Click(object sender, EventArgs e)
        {
            string className = "gps";
            button2_NoEncapsulation(className);
            className = "imu";
            button2_NoEncapsulation(className);
        }

        /// <summary>
        /// 如果不用简单工厂
        /// </summary>
        /// <param name="str1"></param>
        private void button2_NoEncapsulation(string className)
        {
            string str1 = "";
            if (className == "gps")
            {
                Gps e1 = new Gps();
                str1 = e1.GetName();
                Invoke(new show(showTextbox), new object[] { str1 });
            }
            else
            {
                IMU e2 = new IMU();
                str1 = e2.GetName();
                Invoke(new show(showTextbox), new object[] { str1 });
            }
        }

2.3 使用简单工厂的调用

好处是显而易见的,由于做了抽象,调用时候完全统一,即便后续需要增加新的东西,调用该类的业务代码也不需要进行修改,而是把修改的工作提前到了类定义中。

        private void button2_Click(object sender, EventArgs e)
        {
            string className = "gps";
            button2_Encapsulation(className);
            className = "imu";
            button2_Encapsulation(className);
        }

        /// <summary>
        /// 如果用简单工厂
        /// </summary>
        /// <param name="className"></param>
        private void button2_Encapsulation(string className)
        {
            IEquip e3 = EquipSimpleFactory.CreateFactory(className);
            string str1 = e3.GetName();
            Invoke(new show(showTextbox), new object[] { str1 });
        }

三、优缺点和应用场景

看完简单工厂模式的实现之后,肯定会有这样的疑惑(因为我学习的时候也有)——这样我们只是把变化移到了工厂类中罢了,变化点在于:

没应用简单工厂模式之前,修改的是客户类;
现在需要修改工厂类中的方法(也就是多加case语句,)

我首先要说:对的,这个就是简单工厂模式的缺点所在(这个缺点后面介绍的工厂方法可以很好地解决),然而,简单工厂模式与之前的实现也有它的优点。

3.1 优点

  • 1、简单工厂模式解决了客户端直接依赖于具体对象的问题,客户端可以消除直接创建对象的责任,而仅仅是消费产品。简单工厂模式实现了对责任的分割;
  • 2、简单工厂模式也起到了代码复用的作用,因为之前的实现中,调用时需要对每个类创建自己的逻辑,而逻辑是容易出现问题的地方,也是需要测试的地方。使用简单工厂,复用了逻辑代码,减少了修改问题。(同时这点也是简单工厂方法的缺点——因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响,也没什么不好理解的,就如事物都有两面性一样道理);

3.2 缺点

虽然上面已经介绍了简单工厂模式的缺点,下面还是总结下简单工厂模式的缺点:

  • 1、工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响;
  • 2、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,这样就会造成工厂逻辑过于复杂;

3.3 应用场景

了解了简单工厂模式之后的优缺点之后,我们之后就可以知道简单工厂的应用场景了:

  • 1、当工厂类负责创建的对象比较少时可以考虑使用简单工厂模式;
  • 2、客户如果只知道传入工厂类的参数,对于如何创建对象的逻辑不关心时可以考虑使用简单工厂模式;

猜你喜欢

转载自blog.csdn.net/u012692537/article/details/81627245