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:考虑用静态工厂方法代替构造器
用静态工厂方法来代替构造器为外界提供对象 描述: 静态工厂方法代替构造器来给外界提供对象,创建对象依然是由构造器来完成的 创建对象和提供对象: 创建对象的方式: 构造器 提供对象来哦方式: 构造器 类 ...
随机推荐
- Springboot引入本地jar时打包
在项目的开发过程中有时我们需要引入我们本地的jar包,这些jar包没有存在maven仓库中 ,这时没有办法通过pom文件直接引入,在开发过程中我们可以通过add as library的方式,可以在开发 ...
- background-position和position
1.background-position:表示背景定位的属性.描述属性值时,有两种方式:一是像素描述:而是单位描述. (1)像素描述: 格式如下: background-position:向右偏移量 ...
- MOS 常用链接地址
主页面类 Exadata主页面 Exadata Database Machine and Exadata Storage Server Supported Versions (Doc ID 8888 ...
- restframewor 版本(version)
1.路由 a.一级路由 from django.contrib import admin from django.urls import path, include from api import u ...
- 「 从0到1学习微服务SpringCloud 」13 断路器Hystrix
背景与功能 在微服务架构中,很多情况下,各个服务之间是相互依赖,一个服务可能会调用了好几个其他服务,假设其中有一个服务故障,便会产生级联故障,最终导致整个系统崩溃无法使用(这称为雪崩效应),Sprin ...
- mysql--->B+tree索引的设计原理
1.什么是数据库的索引 每种查找算法都只能应用于特定的数据结构之上,例如二分查找要求被检索数据有序,而二叉树查找只能应用于二叉查找树上,但是数据本身的组织结构不可能完全满足各种数据结构(例如,理论上不 ...
- C/C++画一个巨型五角星
把朱老师拉着画了半天 利用正弦定理判断一个点是否是否在五角星内,相对于五角星中心的四个象限特判一下来修改角度,把角度都转化成最上面的角,就差不多了,没仔细调整五角星位置,很丑 当然其实也有更方便的方法 ...
- Git详解之安装
前言 是时候动手尝试下 Git 了,不过得先安装好它.有许多种安装方式,主要分为两种,一种是通过编译源代码来安装:另一种是使用为特定平台预编译好的安装包. 从源代码安装 若是条件允许,从源代码安装有很 ...
- C++内存管理笔记(一)
C++内存分配的四个层面 : 四个层面的比较: 内存分配与释放的测试: ); //512 bytes free(p1); complex<int>* p2 = new complex& ...
- Pycharm如何快捷地交互式运行代码(>>>)
Pycharm如何快捷地交互式运行代码? 问题描述 在Pycharm直接一行行地交互运行已经写好的代码,不需要复制粘贴,怎么调出Pychram的交互式界面. 通过python自带的交互式界面 在搜索栏 ...