首页 > 编程语言 >设计模式-C#实现简单工厂模式

设计模式-C#实现简单工厂模式

时间:2024-07-17 09:12:20浏览次数:13  
标签:Convert Console string C# double 工厂 result 设计模式 public

前言

上一篇文章写了如何使用RabbitMQ做个简单的发送邮件项目,然后评论也是比较多,也是准备去学习一下如何确保RabbitMQ的消息可靠性,但是由于时间原因,先来说说设计模式中的简单工厂模式吧!
在了解简单工厂模式之前,我们要知道C#是一款面向对象的高级程序语言。它有3大特性,封装、继承、多态。

简述

工厂模式(Factory Pattern)是一种常用的设计模式,属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式的核心是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。这样客户端可以无需指定具体产品的类,只需通过工厂类即可得到所需的产品对象。

工厂模式主要分为三种类型:简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)和抽象工厂模式(Abstract Factory Pattern)。
本文主要讲解简单工厂模式(Simple Factory Pattern)。

案例带入

下面使用C#控制台程序去写一个简易的计算器,实现加减乘除。如果我没学过设计模式,我会这么写:

static void Main(string[] args)  
{  
    Console.WriteLine("请输入数字A:");  
    string A = Console.ReadLine();  
    Console.WriteLine("请选择运算符号:(+、-、*、/):");  
    string op = Console.ReadLine();  
    Console.WriteLine("请输入数字B:");  
    string B = Console.ReadLine();  
    string result = "";  
    switch (op)  
    {        
	    case "+":  
            result = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(B));  
            break;  
        case "-":  
            result = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(B));  
            break;  
        case "*":  
            result = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(B));  
            break;  
        case "/":  
            result = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(B));  
            break;  
        default:  
            Console.WriteLine("输入的运算符号有误!");  
            break;  
    }    
    Console.WriteLine("结果:" + result);  
}

上述代码乍一看没问题,实则隐藏了很多陷阱,比如:

  1. 变量命名不规范
  2. 除数为0怎么办
  3. 输入的不是数字怎么办
  4. ......

优化

我们用面向对象的思想进行优化,主要体现在:可维护、可复用、可扩展、灵活性几个方面。通过封装、继承、多态来降低程序的耦合度。

封装

我们可以将运算逻辑封装成一个方法去实现,让主方法减轻负担。封装后:
Operation

public class Operation
{
    public static double GetResult(double num1, double num2, string op)
    {
        double result = 0d;
        switch (op)
        {
            case "+":
                result = num1 + num2;
                break;
            case "-":
                result = num1 - num2;
                break;
            case "*":
                result = num1 * num2;
                break;
            case "/":
                result = num1 / num2;
                break;
        }
        return result;
    }
}

Main方法

static void Main(string[] args)
{
	try
	{
		Console.WriteLine("请输入数字A:");
		string strNumA = Console.ReadLine();
		Console.WriteLine("请选择运算符号:(+、-、*、/):");
		string op = Console.ReadLine();
		Console.WriteLine("请输入数字B:");
		string strNumB = Console.ReadLine();
		string result = "";
		result = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumA), Convert.ToDouble(strNumB), op));
		Console.WriteLine("结果:" + result);
	}
	catch (Exception e)
	{
		Console.WriteLine("发生异常:" + e.Message);
	}
}

松耦合

当我们完成封装后开始思考一个问题,如果后面有新的需求,需要增加一个开根运行,应该如何去修改?如果是我,我会在switch里面加一个分支,但是这样耦合度太高。我明明只需要去开根,但是却要让加减乘除参与进来,所以我们应该将加减乘除运算分离出来。
优化耦合度:

public class Operation
{
    private double _num1;
    private double _num2;
    public double Num1 { get => _num1; set => _num1 = value; }
    public double Num2 { get => _num2; set => _num2 = value; }
    public virtual double GetResult()
    {
        return 0;
    }
}

//加法类
public class AddOperation : Operation
{
    public override double GetResult()
    {
        return Num1 + Num2;
    }
}
//减法类
public class SubtractOperation : Operation
{
    public override double GetResult()
    {
        return Num1 - Num2;
    }
}
//乘法类
public class MultiplyOperation : Operation
{
    public override double GetResult()
    {
        return Num1 * Num2;
    }
}
//除法类
public class DivideOperation : Operation
{
    public override double GetResult()
    {
        if (Num2 == 0)
            throw new DivideByZeroException("除数不能为0");
        return Num1 / Num2;
    }
}  

我创建了Operation基类,并定义了2个成员变量_num1_num2,同时定义了一个GetResult虚方法。同时分别创建了加减乘除子类去重写GetResult方法来降级耦合度。

回归正题(简单工厂模式)

我们需要通过简单工厂模式,来让程序知道该实例化谁。需要来创建一个工厂类:

public class OperationFactory
{
    public static Operation CreateOperation(string operation)
    {
        switch (operation)
        {
            case "+":
                return new AddOperation();
            case "-":
                return new SubtractOperation();
            case "*":
                return new MultiplyOperation();
            case "/":
                return new DivideOperation();
            default:
                return null;
        }
    }
}

创建了工厂类有什么好处呢,好处就是,只需要输入运算符号,工厂就能自己实例化出合适的对象,通过多态,返回父类的方法实现了计算器的计算结果。
Main方法
通过简单工厂模式,让我们在计算加减乘除的时候只需要去增加对应的子类就行了,下面的代码进行加法运行时,通过传入+号让工厂去帮我们实例化子类。

static void Main(string[] args)  
{  
    try  
    {  
        // 简单工厂模式  
        var oper = OperationFactory.CreateOperation("+");  
        oper.Num1 = 10;  
        oper.Num2 = 5;  
        Console.WriteLine(oper.GetResult());  
    }    
    catch (Exception e)  
    {        
    Console.WriteLine("发生异常:" + e.Message);  
    }
}

类图

讲完简单工厂模式后,简简单单复现一下类图:
image

小小知识点

  • 接口:强调“做什么”,即接口定义了对象应该做什么,而不关心它是如何做的。
  • 虚方法:强调“如何做”,即基类提供了一种实现方式,但允许派生类根据需要进行修改。

参考资料

  • 熟读并反复背诵大话设计模式-程杰出版

标签:Convert,Console,string,C#,double,工厂,result,设计模式,public
From: https://www.cnblogs.com/ZYPLJ/p/18306505

相关文章

  • LVM FS NFS CIFS NAS 等存储概念解析
    存储:    LVM:存储的格式,块存储。    FS:文件系统,在LVM的创建的磁盘的基础上,安装FS,形成了文件存储。    NFS:Unix系统间实现磁盘文件共享的一种方法,支持应用程序在客户端通过网络存取位于服务器磁盘中数据的一种文件系统协议。其实它包括许多种协议,最简单的网络文......
  • Apache基于IP和端口
    Apache基于IP步骤1:添加并配置虚拟网卡添加虚拟网卡:通常在虚拟机环境中,可以通过虚拟机软件(如VMware或VirtualBox)的网络设置来添加额外的网络适配器。配置IP地址:编辑/etc/sysconfig/network-scripts/ifcfg-ethX文件,,并将它们设置为静态IP地址。vi/etc/sysconfig/network-scrip......
  • C# Winform PropertyGrid中文排序
    在WindowsForms中,PropertyGrid控件默认按照属性名称的字典顺序(通常是ASCII码顺序)来排序显示属性。这在处理中文字符时可能会导致不自然的排序,因为中文字符的编码顺序与中文的实际字典序不同。为了在PropertyGrid中实现中文属性的自然排序,你可以通过以下方式之一来实现:采用制......
  • 未公开 泛微OA E-Cology 某接口SQL注入漏洞
    0x01阅读须知        技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者......
  • 0day 新接口泛微e-cology getHendledWorkflowRequestList SQL注入漏洞
    0x01阅读须知        技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者......
  • PCDN技术如何应对网络延迟问题?
    PCDN技术通过以下几种方式应对网络延迟问题:去中心化分发:与传统的CDN不同,PCDN利用用户的闲置带宽和存储资源来共享和传递内容。这意味着内容不再仅仅依赖于中心化的服务器进行分发,而是可以通过多个用户设备同时进行分发。这种去中心化的分发方式有效分散了网络流量,降低了服......
  • C++ 多态:探索对象的动态行为
    C++多态:探索对象的动态行为在C++中,多态性是一种强大的特性,它允许我们通过基类指针或引用来调用派生类的方法。多态性不仅增加了程序的灵活性,还使得代码更加易于扩展和维护。本文将深入探讨C++中的多态性,包括静态多态(主要通过函数重载和模板实现)和动态多态(主要通过虚函数......
  • C++ 数据抽象:构建高效、可维护的代码基石
    C++数据抽象:构建高效、可维护的代码基石在软件开发中,数据抽象是一个核心概念,它允许我们隐藏实现细节,仅通过公共接口与外部世界交互。这种封装机制不仅提高了代码的安全性,还促进了代码的复用和可维护性。C++作为一门强大的面向对象编程语言,通过类(Classes)和接口(Interfaces,尽......
  • C++ 重载运算符与重载函数:深入解析与实例
    引言在C++中,重载(Overloading)是一个强大的特性,它允许我们为函数或运算符提供多个定义,这些定义之间通过参数的数量、类型或顺序来区分。重载运算符和重载函数是C++面向对象编程中常见的实践,它们不仅增强了代码的可读性和易用性,还使得类能够模拟内置数据类型的行为。本文将深......
  • Google Colab 云端硬盘路径读取
    加载云端硬盘需要在左上角点击这个文件图标;fromgoogle.colabimportdrivedrive.mount("/content/drive")#挂载云端硬盘importospath="/content/drive/MyDrive/TextClassificationCustom"os.chdir(path)#以路径path作为当前工作目录os.listdir(path)curre......