设计模式(九)之工厂模式

简介: 工厂模式:定义一个用于创建对象的接口,让子类来决定实例化哪一个类,工厂方法使一个类的实例化延迟到子类。

QQ图片20220424155453.jpg

工厂模式:定义一个用于创建对象的接口,让子类来决定实例化哪一个类,工厂方法使一个类的实例化延迟到子类。


之前我们看过简单工厂类,使用的是计算器作为例子。代码如下:


简单工厂类Factory.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
  /// 简单工厂类
namespace simpleFactory
{
    public class Factory
    {
        public static Ireckon CreateTreckon(string signStr)
        {
            Ireckon reckon = null;
            switch (signStr)
            {
                case "+":
                    reckon = new Plus();
                    break;
                case "-":
                    reckon = new Cut();
                    break;
                case "*":
                    reckon = new Ride();
                    break;
                default:
                    Console.WriteLine("暂不支持您输入的运算符");
                    break;
            }
            return reckon;
        }
    }
}


下面我们使用工厂模式来实现这个例子:


先构建一个工厂接口。


然后加减乘除各建一个具体的工厂去实现这个接口。


定义一个算法接口,一个工厂接口,算法类继承算法接口,算法工厂类继承工厂接口(每个算法类都需要有个算法工厂类来对应),将区分运算符号的逻辑部分放到客户端。我们再增加算法的时候,只需要增加对应的算法类。算法工厂类,及修改客户端即可,这样不违反开放封闭原则。


代码如下:


算法类:Ireckon.cs


namespace simpleFactory
{
    public interface Ireckon
    {
        double getResult(double strNumberA, double strNumberB);
    }
}


工厂类:IForecty.cs


namespace simpleFactory
{
    public interface IForecty
    {
        /// <summary>
        /// 工厂类:返回计算方法
        /// </summary>
        Ireckon CreateReckon();
    }
}


减法类:Cut.cs


namespace simpleFactory
{
    public class Cut:Ireckon
    {
        public double result;
        public double getResult(double strNumberA, double strNumberB)
        {
            result = strNumberA - strNumberB;
            return result;
        }
    }
}


减法工厂类:CutFactory.cs


namespace simpleFactory
{
    public class CutFactory:IForecty
    {
        public Ireckon CreateReckon()
        {
            return new Cut();
        }
    }
}


加法类:Plus.cs


namespace simpleFactory
{
    public class Plus:Ireckon
    {
        public double result;
        public double getResult(double strNumberA, double strNumberB)
        {
            result = strNumberA + strNumberB;
            return result;
        }
    }
}


加法工厂类:PlusFactory.cs


namespace simpleFactory
{
    public class PlusFactory:IForecty
    {
        public Ireckon CreateReckon()
        {
            return new Plus();
        }
    }
}


乘法类:Ride.cs


namespace simpleFactory
{
    public class Ride:Ireckon
    {
        public double result;
        public double getResult(double strNumberA, double strNumberB)
        {
            result = strNumberA * strNumberB;
            return result;
        }
    }
}


乘法工厂类:RideFactory.cs


namespace simpleFactory
{
    public class RideFactory:IForecty
    {
        public Ireckon CreateReckon()
        {
            return new Ride();
        }
    }
}


客户端:Program.cs


namespace simpleFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            // 数字A
            double strNumberA;
            // 数字B
            double strNumberB;
            // 运算符
            string signStr;
            // 运算结果
            double result;
            try
            {
                Console.WriteLine("请输入第一个数字");
                strNumberA = Convert.ToDouble(Console.ReadLine());
                Console.WriteLine("请输入运算符号");
                signStr = Console.ReadLine();
                Console.WriteLine("请输入第二个数字");
                strNumberB = Convert.ToDouble(Console.ReadLine());
                // 使用简单工厂类返回实例化子类的对象(因为子类中都是重写基类中的方法,指定类型的时候,直接声明基类就可以)
                //Ireckon reckon = Factory.CreateTreckon(signStr);
                //// 调用
                //result = reckon.getResult(strNumberA, strNumberB);
                // 工厂模式实现调用,现在我们再增加算法的时候,只需要增加对应的算法类
                // 算法工厂类,及修改调用部分即可,这样不违反开放封闭原则。
                IForecty reckon = null;
                switch (signStr)
                {
                    case "+":
                        reckon = new PlusFactory();
                        break;
                    case "-":
                        reckon = new CutFactory();
                        break;
                    case "*":
                        reckon = new RideFactory();
                        break;
                    default:
                        Console.WriteLine("暂不支持您输入的运算符");
                        break;
                }
                result = reckon.CreateReckon().getResult(strNumberA, strNumberB);
                Console.WriteLine("运算结果为:" + result);
            }
            catch (Exception qq )
            {
                // 输出错误信息
                Console.WriteLine(qq.Message);
            }
            Console.ReadLine();
        }
    }
}


上边的代码就使用工厂模式实现了简单工厂模式中的例子,代码看起来比简单工厂模式要复杂的多。但是,其更加合理。


简单工厂模式的优点:我们可以对创建的对象进行一些 “加工” ,而且客户端并不知道,因为工厂隐藏了这些细节。如果,没有工厂的话,那我们是不是就得自己在客户端上写这些代码,这就好比本来可以在工厂里生产的东西,拿来自己手工制作,不仅麻烦以后还不好维护。


但是缺点也很明显:如果需要在方法里写很多与对象创建有关的业务代码,而且需要的创建的对象还不少的话,我们要在这个简单工厂类里编写很多个方法,每个方法里都得写很多相应的业务代码,而每次增加子类或者删除子类对象的创建都需要打开这简单工厂类来进行修改。这会导致这个简单工厂类很庞大臃肿、耦合性高,而且增加、删除某个子类对象的创建都需要打开简单工厂类来进行修改代码也违反了开-闭原则。


工厂模式是对简单工厂模式进一步的解耦,因为在工厂方法模式中是一个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口。这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了。

工厂模式中,要增加产品类时也要相应地增加工厂类,客户端的代码也增加了不少。工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。


你想要加功能,本来是改工厂类的,而现在是修改客户端。而且各个不同功能的实例对象的创建代码,也没有耦合在同一个工厂类里,这也是工厂方法模式对简单工厂模式解耦的一个体现。工厂方法模式克服了简单工厂会违背开-闭原则的缺点,又保持了封装对象创建过程的优点。


但工厂方法模式的缺点是每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量。



目录
相关文章
|
存储 JSON 安全
Elasticsearch索引生命周期管理方案
本文主要介绍Elasticsearch索引生命周期管理如何配置和使用
1432 1
Elasticsearch索引生命周期管理方案
|
11月前
|
缓存 Linux
linux 手动释放内存
在 Linux 系统中,内存管理通常自动处理,但业务繁忙时缓存占用过多可能导致内存不足,影响性能。此时可在业务闲时手动释放内存。
524 17
|
7月前
|
人工智能 编解码 自然语言处理
AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡
AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡
234 4
AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡
|
8月前
|
IDE 开发工具 开发者
手把手教你安装PyCharm 2025:开发者的Python IDE配置全流程+避坑指南
本教程详细介绍了PyCharm 2025版本在Windows系统下的安装流程及配置方法,涵盖AI代码补全与智能调试工具链等新功能。内容包括系统要求、安装步骤、首次运行配置(如主题选择与插件安装)、创建首个Python项目,以及常见问题解决方法。此外,还提供了切换中文界面和延伸学习资源的指导,帮助用户快速上手并高效使用PyCharm进行开发。
3961 61
|
11月前
|
算法
基于梯度流的扩散映射卡尔曼滤波算法的信号预处理matlab仿真
本项目基于梯度流的扩散映射卡尔曼滤波算法(GFDMKF),用于信号预处理的MATLAB仿真。通过设置不同噪声大小,测试滤波效果。核心代码实现数据加载、含噪信号生成、扩散映射构建及DMK滤波器应用,并展示含噪与无噪信号及滤波结果的对比图。GFDMKF结合非线性流形学习与经典卡尔曼滤波,提高对非线性高维信号的滤波和跟踪性能。 **主要步骤:** 1. 加载数据并生成含噪测量值。 2. 使用扩散映射捕捉低维流形结构。 3. 应用DMK滤波器进行状态估计。 4. 绘制不同SNR下的轨迹示例。
|
存储 人工智能 自然语言处理
新手指南:微软ai助手Copilot国内如何使用?
微软 Copilot 是一款强大的 AI 助手,掌握一些技巧可以让你更好地利用它,提高效率和创造力,让你的工作和生活更加精彩!
12683 11
|
开发工具
java.lang.unsatisfiedlinkerror解决方法
java.lang.unsatisfiedlinkerror解决方法
1556 1
|
存储 监控 数据管理
如何设置绿联云与PC电脑同步?
【7月更文挑战第1天】如何设置绿联云与PC电脑同步?
3981 2
|
算法 数据可视化 计算机视觉
使用Python实现图像处理中的边缘检测算法
图像处理中的边缘检测是计算机视觉和图像识别领域的重要技术之一。本文将介绍如何利用Python语言实现常见的边缘检测算法,包括Sobel、Canny等,并结合实例演示其在图像处理中的应用。
545 16