C#的静态工厂方法与构造函数对比
最近,在与同事进行协同编程时,我们开始讨论在C#中初始化新对象的最佳方法。我一直是使用构造函数实现,尽管他倾向于静态工程方法。这引起了关于每种类型的利弊的大量来来回回的讨论。
为了说明我所说的内容,这是两个例子:
// Using the constructor
SqlConnection myConnection = new SqlConnection(connectionString);
// Using a static factory method
IDbConnection myConnection = SqlConnection.FromConnectionString(connectionString);
之前我从未考虑过实现这些静态工厂方法,我并自嘲问不了解其内容。自从那以后,我改变了注意,让我们深入探讨其优缺点。
静态工厂方法的优点
无须返回一个新的实例
而构造函数总是返回一个新的对象。
当新对象创建失败时,你不能使用一个缓存的对象或返回 null。特别是在编写库代码时,将来可能会很灵活。
你可以使用方法参考
如果你倾向于以一种实用的方式编写C#,你可能会感激你可以在代码中传递该方法(或正式称为“方法组”)的引用。对比一下:
// Static factory method - the method group can be passed in directly as a function reference
var bars = myFoo.Select(bar.FromFoo)
// Constructors - you have to pass in a lambda that constructs the instance via new.
var bars = myFoo.Select(f => new Bar(f));
这段代码没有功能上的差异,只是代码风格上的一个问题。因此可能不应在决策中过分重视。
你能通过名字了解
对于某些对象,尤其是可以通过多种类似方式构造的对象-能够在构造对象的方式上获益良多。让我们以Color类为例,该类可以通过CMYK和RGB参数构造。
// With constructors
var color = new Color(25, 25, 5, 80);
var color = new Color(100, 150, 50);
// With static factory methods
var color = Color.FromCMYK(25, 25, 5, 80);
var color = Color.FromRGB(100, 150, 50);
与更具描述性的静态工程方法进行对比,除非你知道Color的四个值的构造函数是CMYK,三个值的构造函数是RGB,否则无法通过阅读代码来区别出来。
我认为,如果你有不同的构造对象的方式,尤其是参数彼此相似的方式,有很充分的理由来使用静态工厂方法。
工厂方法可以返回不同的类
new Foo()总是返回一个Foo类的一个新的实例,Foo.FromBar很容易的返回一个IFoo接口,或者Foo的一个子类。一个可能与之相关的真实示例:
// This could create an IpV4IpAddress that implements IIpAddress
IIpAddress ipv4Address = IpAddress.FromString("127.0.0.1");
// This could create an IpV6IpAddress that implements IIpAddress
IIpAddress ipv6Address = IpAddress.FromString("2001:0db8:0a0b:12f0:0000:0000:0000:0001")
在提供公共API(例如在库上下文中)时,能够根据输入返回不同的实际类型可能非常有价值。特别是因为这意味着你可以在接口或者基类后面隐藏一些实现细节。
我不确定应用程序代码中的价值是否一样大,你可以在其中控制整个库代码,并使大规模重构变得更加容易。
在构造函数中你不应该做的事情
通常,人们并不期望构造函数除了构造对象之外,还能做其他很多事情。你管你可以在构造函数中执行I/O,数据库访问等操作,但大多数人并不期望这样做。按照惯例,你可以自由的以静态工厂方法执行更多的工作,而无需任何人引起注意。
有些人也不认为你应该在构造函数中抛出异常。也许这取决于语言,但在C#中完全可以,如果要在构造函数中创建非托管资源,请注意一下几点。
静态工厂方法的缺点
在构造函数中不应该做的事情
按照惯例,构造函数通常更简单。当我调用构造函数时,通常不希望它执行I/O或
其他。这使构造函数的构造灵活性大大降低,这既是福也是祸。
意味着更多代码
无论如何,你仍然需要构造函数来实际构造对象。静态工厂方法是更多的代码,而代码是一中责任。它通常不是很复制的代码,并且通常静态工厂方法也不是特别长,因此这可能不是一个很大的缺点。
很难找到
通常,当我尝试构造一个新对象时,我会先寻找构造函数。通过自动完成功能很难找到静态方法,因为他们通常无法与其他静态方法区分开。
我认为静态方法最大的问题是你失去了可发现性。
经过研究和思考之后,我认为我目前的看法是:
- 你应该始终创建一个构造函数,该构造函数将1:1映射到类内部的字段
- 如果你需要花很多实践来创建对象(例如IO),或者对缓存对象并重新使用它们感兴趣,请使用静态工厂方法。
- 如果你需要API稳定(例如用于库开发),请隐藏该构造函数并使用静态工厂方法,因为它为你提供了实现的灵活性.
- 如果你有多种不同的方法来创建类,请创建静态工厂方法并使用它们,因为它们为你提供了描写性.
C#的静态工厂方法与构造函数对比的更多相关文章
- 比较 Java 静态工厂方法与构造函数
1 什么是静态工厂方法 Java 静态工厂方法是在方法前加上 public static,让这个方法变为公开.静态的方法.该方法返回该类的一个实例,就好像一个工厂生产出一个产品.所以称之为静态工厂方法 ...
- ej3-1优先使用静态工厂方法而非构造函数来创建对象
背景 很早之前就已经自己翻译了,先简单的贴出来,并做一下回顾. 条款1 优先使用静态工厂方法而非构造函数来创建对象 允许客户端创建一个实例的传统方法是:提供一个公共构造函数:有另外一个必须成为每个程序 ...
- <创建和销毁对象>经验法则——考虑用静态工厂方法代替公有构造方法
一.引出静态工厂方法 对于java类而言,为了让使用者获取它自身的一个实例化对象,会有以下方法: 1.该类提供一个公有的构造方法.在这种情况下,程序可以通过多个“new 构造方法”语句来创建类的任意多 ...
- 创建对象_工厂方法(Factory Method)模式 与 静态工厂方法
工厂方法模式: 定义:为创建对象定义一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟至子类. 应用场景: 客户类不关心使用哪个具体类,只关心该接口所提供的功能: 创建过程比较 ...
- java的设计模式 - 静态工厂方法
静态工厂方法,也不知道为何叫这个名字.其实也就是一个静态函数,可以替代构造函数用.大名鼎鼎的 guava 就大量使用这种模式,这是非常有用的模式. 比如是 Integer i = Integer.va ...
- Java 的静态工厂方法
本文转载自:https://www.jianshu.com/p/ceb5ec8f1174 序:什么是静态工厂方法 Effective Java 2.1 静态工厂方法与构造器不同的第一优势在于,它们有名 ...
- 静态工厂方法和实例工厂方法及普通的bean
容纳你的bean bean工厂:最简单的容器,提供了基础的依赖注入支持.创建各种类型的Bean. 应用上下文(ApplicationContext):建立在bean工厂基础之上,提供系统架构服务. ...
- Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...
- Tips1:考虑用静态工厂方法代替构造器
用静态工厂方法来代替构造器为外界提供对象 描述: 静态工厂方法代替构造器来给外界提供对象,创建对象依然是由构造器来完成的 创建对象和提供对象: 创建对象的方式: 构造器 提供对象来哦方式: 构造器 类 ...
随机推荐
- MacOSX 安装 TensorFlow
TensorFlow是一个端到端开源机器学习平台.它拥有一个包含各种工具.库和社区资源的全面灵活生态系统,可以让研究人员推动机器学习领域的先进技术的. 准备 安装 Anaconda TensorFlo ...
- 如何学习理解Redux Middleware
Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会.可以允许我们添加自己的逻辑在这段当中.它提供的是位于 action 被发起之后 ...
- c语言-输出圆形
#include<stdio.h> #define high 100//定义界面大小 #define wide 100 void Circle(int ridus) //确定坐标 {int ...
- Centos 7中安装svn服务器,史上最详细
最近上头安排了帮客户安装svn服务器,用了两种方式安装,yum命令安装,快速简洁容易上手,但是源码安装就比较繁琐,两种方式都试了一下,yum命令基本一个多小时就安装完了,但是源码安装弄了我两天的时间, ...
- Docker扩展内容之容器开机自启
前言 部署项目服务器时,为了应对停电等情况影响正常web项目的访问,会把Docker容器设置为开机自动启动. 在使用docker run启动容器时,使用--restart参数来设置,具体参数如下详解 ...
- vue2.x中子组件修改父组件通过pops传递过来的值
首先,父组件向子组件传值 这里面主要是在传值的时候,加上.sync 然后子组件通过 $emit 修改 如此即可完成对父组件的数据操作
- QtGui实现计算圆的面积
dialog.h #ifndef DIALOG_H #define DIALOG_H #include <QtWidgets/QDialog> #include <QtWidgets ...
- gentoo在KVM+QEMU中安装笔记
gentoo是比较难安装的,本笔记主要是记录本次安装过程,以备参考. 1.首先,下载镜像,可以去国内各大镜像网站下载,我选择的是清华的镜像源:https://mirrors.tuna.tsinghua ...
- 视觉slam十四讲课后习题ch3--5题
题目回顾: 假设有一个大的Eigen矩阵,我想把它的左上角3x3块提取出来,然后赋值为I3x3.编程实现.解:提取大矩阵左上角3x3矩阵,有两种方式: 1.直接从0-2循环遍历大矩阵的前三行和三列 2 ...
- 关于Icon,Image,ImageIcon的简单的对比参考
Icon: Icon位于javax.swing包中,它是一个接口 public interface Icon,介绍为:一个小的固定大小的图片,通常用于装饰组件 有三个方法: int getIconHe ...