Simple Factory Pattern 简单工厂模式简介与 C# 示例【创建型】【设计模式来了】

 〇、简介

1、什么是简单工厂模式?

一句话解释:

  客户类和工厂类严格分工,客户类只需知道怎么用,处理逻辑交给工厂类。

简单工厂模式(Simple Factory Pattern)是日常开发中常用的设计模式。其是一种简单的创建型模式,它通过一个工厂类来创建对象,客户端只需要知道如何使用工厂类,而不需要知道对象的实现细节。工厂类负责创建对象的整个生命周期,并且负责处理与具体实现有关的逻辑。

这种将变化逻辑和客户端分离的方式,就是面向对象中的“封装”特性了。

 一个比喻:(食堂与学生)

  比如一个食堂中午有各种面食,学生也就是客户端,关心的是菜单想吃哪个就给直接说,不关心这份焖面或者烩面怎么做的,后厨就相当于工厂类,把控着制作的步骤。

2、优缺点和使用场景

  • 优点:简单工厂模式可以使客户端代码变得简洁,同时隐藏对象的实现细节。
  • 缺点:当需要增加新的运算类时,需要修改工厂类的代码,这违反了开闭原则。此外,工厂类包含了一组相关对象的创建逻辑,这使得工厂类变得复杂,难以维护。

 使用场景举例:

  • 客户端如果对于如何创建对象的逻辑不关心,且知道工厂类的入参时,可以考虑使用简单工厂模式。
  • 当工厂类负责创建的对象比较少时可以考虑使用简单工厂模式,因为比较多的话 case 太多维护起来较麻烦。

二、简单工厂模式的简单实现与比较

 如下代码,是一个画形状的示例:

// 形状接口,画动作的方法
public interface IShape
{
    void Draw();
}
public class Circle : IShape
{
    public void Draw()
    {
        Console.WriteLine("画圆:〇");
    }
}
public class Rectangle : IShape
{
    public void Draw()
    {
        Console.WriteLine("画方:口");
    }
}
public class ShapeFactory // 简单工厂实现
{
    public static IShape CreateShape(string shapeType)
    {
        switch (shapeType) // 当需要扩展时,就需要修改这里的 case 也是本模式的缺点所在
        {
            case "圆":
                return new Circle();
            case "方":
                return new Rectangle();
            default:
                throw new ArgumentException("输入形状不支持!");
        }
    }
}

测试代码: 

static void Main(string[] args)
{
    // 简单工厂模式写法
    IShape circle = ShapeFactory.CreateShape("圆"); // 把对象的创建交给工厂类
    circle.Draw();
    IShape rectangle = ShapeFactory.CreateShape("方");
    rectangle.Draw();
    // 不用简单工厂模式的写法
    Circle circle = new Circle(); // 单个类实例化,把创建对象的工作放在了客户端
    circle.Draw();
    Rectangle rectangle = new Rectangle();
    rectangle.Draw();
}

结果是相同的:

   

三、在 .NET 框架中的实际应用

 .NET 中 System.Text.Encoding 类就实现了简单工厂模式,该类中的 GetEncoding(int codepage) 就是工厂方法,具体的代码可以通过 ILSpy 反编译工具进行查看,下面就是该方法中的代码:

// System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
// System.Text.Encoding
using System.Globalization;

public static Encoding GetEncoding(int codepage)
{
    Encoding encoding = FilterDisallowedEncodings(EncodingProvider.GetEncodingFromProvider(codepage));
    if (encoding != null)
    {
        return encoding;
    }
    switch (codepage)
    {
        case 0:
            return Default;
        case 1200:
            return Unicode;
        case 1201:
            return BigEndianUnicode;
        case 12000:
            return UTF32;
        case 12001:
            return BigEndianUTF32;
        case 65001:
            return UTF8;
        case 20127:
            return ASCII;
        case 28591:
            return Latin1;
        case 1:
        case 2:
        case 3:
        case 42:
            throw new ArgumentException(SR.Format(SR.Argument_CodepageNotSupported, codepage), "codepage");
        case 65000:
            {
                if (LocalAppContextSwitches.EnableUnsafeUTF7Encoding)
                {
                    return UTF7;
                }
                string p = string.Format(CultureInfo.InvariantCulture, "http://aka.ms/dotnet-warnings/{0}", "SYSLIB0001");
                string message = SR.Format(SR.Encoding_UTF7_Disabled, p);
                throw new NotSupportedException(message);
            }
        default:
            if (codepage < 0 || codepage > 65535)
            {
                throw new ArgumentOutOfRangeException("codepage", SR.Format(SR.ArgumentOutOfRange_Range, 0, 65535));
            }
            throw new NotSupportedException(SR.Format(SR.NotSupported_NoCodepageData, codepage));
    }
}

public abstract class Encoding : ICloneable
{
    // 。。。
}

 由源码可知,GetEncoding(int) 方法中,例举了全部可用的编码方式,客户端这可以通过编码 codepage 查询目标编码类型。

参考:http://www.cnblogs.com/zhili/p/SimpleFactory.html

本文来自博客园,作者:橙子家,微信号:zfy1070491745,有任何疑问欢迎沟通,一起成长。

转载本文请注明原文链接:http://www.cnblogs.com/czzj/p/SJMSLL_SimpleFactory.html

本文转载于网络 如有侵权请联系删除

相关文章

  • (6)FlinkSQL将kafka数据写入到mysql方式一

    这里不展开zookeeper、kafka安装配置(1)首先需要启动zookeeper和kafka(2)定义一个kafka生产者packagecom.producers; importcom.alibaba.fastjson.JSONObject; importcom.pojo.Event; importcom.pojo.WaterSensor; importorg.apache.kafka.clients.producer.KafkaProducer; importorg.apache.kafka.clients.producer.ProducerRecord; importorg.apache.kafka.clients.producer.RecordMetadata; importorg.apache.kafka.common.serialization.StringSerializer; importjava.util.Properties; importjava.util.Random; /** *Createdbyljon2022-07-09. */ publiccla

  • java的内存泄露是如何发生的,如何避免和发现?

    java的垃圾回收与内存泄露的关系:【新手可忽略不影响继续学习】 马克-to-win:上一节讲了,(i)对象被置成null.(ii)局部对象(无需置成null)当程序运行到右大括号.(iii)匿名对象刚用完,垃圾回收线程就早早晚晚都能把它过去占的内存给回收了。这么说,java中难道就没有c++的内存泄露的问题了吗?(内存泄露的定义就是:咱自己程序不用的内存,系统本应回收但由于各种原因却没有回收成功)马克-to-win:答案:错,java中有内存泄露。下面我们就通过一个例子来说明。下面的例子中,Mark_to_winm作为实例是占有内存空间的。即使后来m=null;把它置为null,垃圾回收线程也回收不了它占有的空间。因为等我们后面集合框架学习了Vector以后,你就会知道:Vectorv是一个类似数组的东西。马克-to-win:任何通过v.add(m);加到Vector里的东西,Vector都会保留一个对它的引用。正因为有这个引用,垃圾回收系统当中的有向图会认为,这个对象还是可达的,所以不会回收它的内存空间。因为size_Make_to_win非常大,(是maxMemory的0.8倍)

  • 树莓派安装 ubuntu 20.04 LTS 碰壁指南

    树莓派安装Ubuntu20.04LTS碰壁指南设备Raspberry4B4+32G 系统Ubuntu20.04LTS 1.镜像下载与烧录镜像下载地址:https://cdimage.ubuntu.com/releases/20.04.1/release/ubuntu-20.04.1-preinstalled-server-arm64+raspi.img.xz烧录工具 SDCardFormatterWin32DiskImager2.启用root账户输入命令后根据提示操作supasswdroot复制3.无线网络连接初始化进入netplan配置文件夹cd/etc/netplan/复制配置无线网sudovim50-cloud-init.yaml复制配置如下,仅供参考#Thisfileisgeneratedfrominformationprovidedbythedatasource.Changes #toitwillnotpersistacrossaninstancereboot.Todisablecloud-init's #networkconfigurationcapabiliti

  • 【分享】涓流充电?UI快充?谈谈手机充电过程

    2019年,是各家手机厂商快充突飞猛进的一年,40w、44w、50w,65w,功率越来越高;2020年,是各家手机厂商快充值得期待的一年,100w、120w,各家实验室都在加速功率“破百”。厂商的进步都非常明显,不过快充带来的一些疑虑还可以挖一挖。 过去,人们常说xx快充砍涓流、伤电池,而如今,有更多厂商开始了类似的行为; 人们发现,一些手机电量显示100%,并非真正充满,而有些手机在报满之后距离停充还有颇长的一段时间。涓流充电?UI快充?到底是指什么,恐怕不少人只是人云亦云,并不知道这两个词语的真正含义。下面就让我“借题发挥”,解释下充电的一些基本概念。才疏学浅,文中我的一些观点可能存在疏漏之处,希望有人可以一起探讨(反正最近闲着也是闲着,是吧)首先,什么是涓流充电? 这需要解释下充电流程。手机电池大多是高压电池,目前苹果惯用电池是4.35V满电,Android厂家惯用电池是4.4V满电。电池就像一个水桶,在完全空掉时要防止过猛的流量把桶底充伤,低位时可以大流量充入,高位时又要小心流速,防止涨裂。所以充电过程就一个先慢→再快→再慢的过程。充电过程就是根据电池电压进行了划分。常见的手机

  • 为了解决 Prometheus 大内存问题,我竟然强行将 Prometheus Operator 给肢解了。。

    想获得更好的阅读体验,可以在浏览器中打开链接 https://fuckcloudnative.io/posts/aggregate-metrics-user-prometheus-operator/ 直接阅读原文Promtheus本身只支持单机部署,没有自带支持集群部署,也不支持高可用以及水平扩容,它的存储空间受限于本地磁盘的容量。同时随着数据采集量的增加,单台Prometheus实例能够处理的时间序列数会达到瓶颈,这时CPU和内存都会升高,一般内存先达到瓶颈,主要原因有:Prometheus的内存消耗主要是因为每隔2小时做一个Block数据落盘,落盘之前所有数据都在内存里面,因此和采集量有关。加载历史数据时,是从磁盘到内存的,查询范围越大,内存越大。这里面有一定的优化空间。一些不合理的查询条件也会加大内存,如Group或大范围Rate。这个时候要么加内存,要么通过集群分片来减少每个实例需要采集的指标。本文就来讨论通过PrometheusOperator部署的Prometheus如何根据服务维度来拆分实例。1.根据服务维度拆分PrometheusPrometheus主张根据功能或服务维

  • 【CPP】游标(静态)链表

    这次的代码基本来自《数据结构与算法分析——C语言描述》这本神书和网上别人写的代码。主要讲一下游标链表的原理。 游标(Cursor)链表,即是用数组和数组下标来代替指针实现链表的一种东西。在许多编程语言中,指针是不被支持的。在这种情况下如果我们需要自己来实现链表(虽然大多数这类语言都不需要自己实现链表),就可以使用数组和游标来实现。由于我们通过声明数组下标变量来代替指针,所以把那个下标变量叫做游标。由于这个链表的储存空间由数组来提供,所以叫做静态链表。 在实现游标链表时,最主要是要模拟出指针(游标),和内存的申请与释放(malloc,free)。这里我们先看看代码头,这次的代码是由纯C的函数构成。 首先我们初始化模拟内存的数组CursorSpace,我们申请一个足够大的数组,然后让这个数组每个元素指向下一位的下标为自己的下一个数,让数组末指向数组头,这样我们就将整个数组内存串成了一个大的循环链表空间,在这里我们让0号位表示空白空间的头。然后这里我们可以看到,每次我们alloc时,函数都会在CursorSpace找到0号位的下一位来返回,然后让0号位指向自己的后一位。这样我们便通过这种指针

  • 使用GDC API查看和下载TCGA的数据

    API是应用程序编程接口,很多的网站都有对应的API,方便程序抓取数据,比如NCBI,EBI,KEGG等等,GDC也有对应的API,可以方便的查询和下载TCGA的数据,API的网址如下https://gdc.cancer.gov/developers/gdc-application-programming-interface-apiAPI都有一个baseurl,通过baseurl加上内置的指令,可以实现特定数据集的访问和下载,GDCAPI的baseurl如下https://api.gdc.cancer.gov/<endpoint> https://api.gdc.cancer.gov/legacy/<endpoint>复制第一种访问和操作GDCharmonizeddatabase,第二种访问和操作GDClegacyarchive。endpoint是内置的指令,支持的指令如下所示从功能上可以划分为查询,下载,提交数据三大块,常用的的功能包括查询和下载1.查询通过JSON这种格式进行数据交换,以files为例,以其对应的uuid为例进行查询的用法如下curlhttp

  • mysql workbench怎么导入数据库sql文件_workbench导入数据

    大家好,又见面了,我是你们的朋友全栈君。第一步,登陆mysqlworkbench第二步,打开自己的数据,此处默认(root)打开数据库后页面:第三步,新建一个schema,随便给个名字,这里起名为test:可以看到test内的table,views,routines,等选项都是没有任何内容的。第四步,在file下打开你需要导入的.sql文件。第五步,(关键步骤)在打开的文件当中,除去注释外的第一行,添加一行代码,useschema名。第六步,点击打开文件上的小闪电标志,执行代码。第七步,查看数据库是否已经导入(新建的test库)OK完成入库。发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/189168.html原文链接:https://javaforall.cn

  • C语言-字符串函数的实现(五)之strstr

    C语言中的字符串函数有如下这些 获取字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strncat strncmp 字符串查找 strstr strtok 错误信息报告 strerror 字符串查找 strstr 还是一样,先看看如何使用它,对吧哈哈哈。 intmain() { char*p1="abcdef"; char*p2="def"; //在abcdef中找找def,找到的话返回它的地址,找不到返回空指针 char*rest=strstr(p1,p2); if(rest==NULL) { printf("子串不存在\n"); } else { printf("%s\n",rest); } return0; } 复制 老规矩,我们还是看看文档是怎样说的,如下 strstr文档 char*strstr(constchar*str1,constchar*str2); 复制 Returnsapointertothefirstoccurrenceofstr2inst

  • MySQL索引设计需要考虑哪些因素?

    索引小知识 篇幅有限,索引的基本知识我们就不赘述了,在此,我们尝试说明其中的一个小点-----B+树与B树的区别到底是什么。 InnoDB是使用B+树来实现其索引功能的。在B+树中,内节点(非叶子节点)存储了行数据的键,而叶子节点存储了所有的行数据,而B树的每个节点都存储了真实的数据。这种数据结构,决定了两者有以下不同点: (1)非叶子节点能存放指针的数据量。因为B树的非叶子节点存放的是整行的数据,占用了较多的空间,所以能存放指针就相对较少,因此整个B树的层数就变高。当数据量比较大时,插入更新会导致维护代价也是比较大的,而且层数越高,搜索的性能就会越低。而B+树的内节点存放的是相对短很多的键值,就克服了B树遇到的问题。 (2)从数据结构上来看,B树的查询效率与数据所在的位置有关。即如果所要搜索的数据节点,在树上的位置,越靠近根节点,查询返回结果越快,最差的就是数据位于叶子节点上,不同的节点位置,其性能不均衡;而B+树,完整的数据都是在叶子节点上,其查询效率是固定的。插入、删除操作同样的原理,在B树中,其复杂度明显增加,而B+树相对简单的多。例如,B+树,在插入过程中,只需要通过在每一层

  • Python之pymysql的使用

    在python3.x中,可以使用pymysql来MySQL数据库的连接,并实现数据库的各种操作,本次博客主要介绍了pymysql的安装和使用方法。   PyMySQL的安装 一、.windows上的安装方法: 在python3.6中,自带pip3,所以在python3中可以直接使用pip3去安装所需的模块: pip3installpymysql-ihttps://pypi.douban.com/simple复制 二、.linux下安装方法: 1.tar包下载及解压 下载tar包 wgethttps://pypi.python.org/packages/29/f8/919a28976bf0557b7819fd6935bfd839118aff913407ca58346e14fa6c86/PyMySQL-0.7.11.tar.gz#md5=167f28514f4c20cbc6b1ddf831ade772 解压并展开tar包 tarxfPyMySQL-0.7.11.tar.gz复制 2.安装 [root@localhostPyMySQL-0.7.11]#python36se

  • SQL Server

    SQLServer中判断数据库是否存在:  法(一):       select*Frommaster.dbo.sysdatabaseswherename='数据库名'   法(二):    ifdb_id('数据库名')isnotnull       dropdatabase。。。     go     create。。。  SQLServer中判断表对象是否存在:  selectcount(*)fromsysobjectswhereid=object_id('数据库名.Owner.表名')   ifexists        (selectcount(*)fromsysobjectswhereid=object_id('数据库名.Owner.表名'))    print'存在'  else    print'不存在' SQLServer中判断表中字段是否存在:  ifexists       (select*fromsyscolumnswherename='colname1'andid=object_id('数据库名.Ow

  • 消息系统kafka原理解析

    Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、ApacheStorm、Spark等都支持与Kafka集成。一、kafka体系架构一个典型的Kafka体系架构包括若干Producer(可以是服务器日志,业务数据,页面前端产生的pageview等等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干Consumer(Group),以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,选举leader,以及在consumergroup发生变化时进行rebalance。Producer使用push(推)模式将消息发布到broker,Consumer使用pull(拉)模式从broker订阅并消费消息。名词解释:名称解释Broker消息中间件处理节点,一个Kafka节点就是一个broker,一个或者多个Broker可以组成一个Kafka集群TopicKafka根据topic对消

  • volatile关键字的理解,不能保证修改的原子性

    voliate关键字基于c++,以及更底层汇编实现,在线程对于本地内存中值修改完成,也就是assigh原子操作结束以后。 会立马对内存中这个数据加锁,也成为内存屏障,这个时候通过mesi或者总线协议其他线程中这个值就会失效,从而保证了修改的可见性。 但是如果其他线程在此时已经修改了本地内存中这个值副本的值,但是还没来得及assigh回去,这个时候这个修改就丢失了。 voliate关键字修饰的变量,发生修改,一般有四个阶段: 从主内存从读取变量副本到本地内存readload 然后是useassigh 此时lock主内存中数据 然后storewrite 其中readloaduseassigh都不能保证原子性,只有最后写入的时候能保证原子性。  

  • 日报11.5

    毕业设计日报 时间:2020年  11 月5日 序号 工作任务 完成情况 待解决问题 解决方法 备注 1 对政策对比的代码进行修改。 完成       今日工作计划 对政策演变的展示进行修改。  

  • Android stdio build.gradle buildscript 里面的repositories 和allprojects里面 repositories 的区别

    第一段 buildscript里面的repositories表示只有编译工具才会用这个仓库。比如buildscript里面的dependenciesclasspath'com.android.tools.build:gradle:2.2.2' buildscript{ repositories{ jcenter() maven{ url'https://maven.google.com/' name'Google' } } dependencies{ classpath'com.android.tools.build:gradle:2.2.2' } } 复制 第二段: allprojects里面的repositories表示项目里面每个gradle里面的库,会依赖用这些仓库。 allprojects{ repositories{ //添加下面的内容 flatDir{ dirs'libs' } jcenter() mavenCentral() maven{ url'https://maven.google.com/' name'Google' } } 复制 比如项目里面的

  • iOS中AutoLayer自动布局流程及相关方法

    关于UIView的Layer,IOS提供了三个方法: 1、layoutSubviews 在iOS5.1和之前的版本,此方法的缺省实现不会做任何事情(实现为空),iOS5.1之后(iOS6开始)的版本,此方法的缺省实现是使用你设置在此view上面的constraints(Autolayout)去决定subviews的position和size。UIView的子类如果需要对其subviews进行更精确的布局,则可以重写此方法。只有在autoresizing和constraint-basedbehaviorsofsubviews不能提供我们想要的布局结果的时候,我们才应该重写此方法。可以在此方法中直接设置subviews的frame。我们不应该直接调用此方法,而应当用下面两个方法。 2、setNeedsLayout 此方法会将view当前的layout设置为无效的,并在下一个upadtecycle里去触发layout更新。 3、layoutIfNeeded 使用此方法强制立即进行layout,从当前view开始,此方法会遍历整个view层次(包括superviews)请求layout。因此,

  • Java集合面试题汇总篇

    文章收录在GitHubJavaKeeper,N线互联网开发必备技能兵器谱 作为一位小菜”一面面试官“,面试过程中,我肯定会问Java集合的内容,同时作为求职者,也肯定会被问到集合,所以整理下Java集合面试题 说说常见的集合有哪些吧? HashMap说一下,其中的Key需要重写hashCode()和equals()吗? HashMap中key和value可以为null吗?允许几个为null呀? HashMap线程安全吗?ConcurrentHashMap和hashTable有什么区别? List和Set说一下,现在有一个ArrayList,对其中的所有元素按照某一属性大小排序,应该怎么做? ArrayList和Vector的区别 list可以删除吗,遍历的时候可以删除吗,为什么 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,需要将对象进行存储,集合就是存储对象最常用的一种方式,也叫容器。 从上面的集合框架图可以看到,Java集合框架主要包括两种类型的容器 一种是集合(Collection),存储一个元素集合 另一种是图(Map),存储键/值对映射

  • TiDB Lightning导入超大型txt文件实践

    背景 TiDB提供了很多种数据迁移的方式,但这些工具/方案普遍对MySQL比较友好,一旦涉及到异构数据迁移,就不得不另寻出路,借助各种开源或商业的数据同步工具。其实数据在不同系统的流转当中,有一种格式是比较通用的,那就是txt/csv这类文件,把数据用约定好的分隔符换行符等标记存放在一起,比如最常见的逗号分隔: aa,11,a1 bb,22,b2 复制 这个文件可以保存为data.txt或者data.csv,一般主流的数据库都支持把这类文件直接导入到对应的表中。 csv本身就是逗号分隔符文件,但是由于逗号太常见了很容易和真实数据混淆,往往会用比较复杂的字符作为分隔符,这时候txt文件就更灵活一些。 在TiDB中我们想导入csv文件可以选择的方式有LoadData和Lightning,但是从官方文档得知,这两种方式都没有明确表示支持txt文件导入。但是经过实测,实际上都能够支持txt格式文件,LoadData参考csv导入即可,本文重点介绍Lightning如何导入txt数据,毕竟数据量很大的时候还得靠Lightning。 有人可能会质疑,不就是改个文件扩展名就能解决的问题何必搞得这么

  • EF vs ADO.NET

    EF有什么缺点,什么时候需要考虑用ADO.NET http://blog.sina.com.cn/s/blog_4aedf6370102wgxl.html  

  • Django简单应用的实现

    Django简单应用的实现 目录介绍: db.sqlite3:split数据库 manage.py:Django工程启动文件;项目管理器:与项目进行交互的命令行工具集的入口 MyFirstDjango asgi.py: 与ASGI兼容的web服务器为您的项目提供服务的入口点。 settings.py: 项目的总配置文件 里面包含了数据库、Web应用、时间等各种配置 urls.py: url配置文件 Django项目中所有地址(页面)都需要我们自己去配置其URL views.py 处理用户发出的请求,从urls.py中对应过来,通过渲染templates中的网页可以将显示内容 wsgi.py WSGI(PythonWebServerDatewayInterface):Python服务器网关接口 Python应用与Web服务器之间通信的接口 static:存放资源文件目录(css/js......) templates:存放HTML页面目录 index.html:HTML页面 简单

相关推荐

推荐阅读