Provider is not a pattern by Mark Seemann

车联网ECU、TSP与TBOX通信流程 对比维度ECU(电子控制单元)BMS(电池管理系统)应用场景传统燃油车 + 新能源汽车仅限新能源汽车核心作用控制整车各系统运行管理动力电池安全与寿命车联网角色数据采集与传输的核心载体提供电池相关的核心数据。 阅读详情

Developers exposed to ASP.NET are likely to be familiar with the so-called Provider pattern. You see it a lot in that part of the BCL: Role Provider, Membership Provider, Profile Provider, etc. Lots of text has already been written about Providers, but the reason I want to add yet another blog post on the topic is because once in a while I get the question on how it relates to Dependency Injection (DI).

Is Provider a proper way to do DI?

No, it has nothing to do with DI, but as it tries to mimic loose coupling I can understand the confusion.

First things first. Let’s start with the name. Is it a pattern at all? Regular readers of this blog may get the impression that I’m fond of calling everything and the kitchen sink an anti-pattern. That’s not true because I only make that claim when I’m certain I can hold that position, so I’m not going to denounce Provider as an anti-pattern. On the contrary I will make the claim that Provider is not a pattern at all.

A design pattern is not invented - it’s discovered as a repeated solution to a commonly recurring problem. Providers, on the other hand, were invented by Microsoft, and I’ve rarely seen them used outside their original scope. Secondly I’d also dispute that they solve anything.

That aside, however, I want to explain why Provider is bad design:

  1. It uses the Constrained Construction anti-pattern
  2. It hides complexity
  3. It prevents proper lifetime management
  4. It’s not testable

In the rest of this post I will explain each point in detail, but before I do that we need an example to look at. The old OrderProcessor example suffices, but instead of injecting IOrderValidator, IOrderCollector, and IOrderShipper this variation uses Providers to provide instances of the Services:

public SuccessResult Process(Order order)
{
    IOrderValidator validator = 
        ValidatorProvider.Validator;
    bool isValid = validator.Validate(order);
    if (isValid)
    {
        CollectorProvider.Collector.Collect(order);
        ShipperProvider.Shipper.Ship(order);
    }

    return this.CreateStatus(isValid);
}

The ValidatorProvider uses the configuration system to create and return an instance of IOrderValidator:

public static IOrderValidator Validator
{
    get 
    {
        var section = 
            OrderValidationConfigurationSection
                .GetSection();
        var typeName = section.ValidatorTypeName;
        var type = Type.GetType(typeName, true);
        var obj = Activator.CreateInstance(type);
        return (IOrderValidator)obj;
    }
}

There are lots of details I omitted here. I could have saved the reference for later use instead of creating a new instance each time the property is accessed. In that case I would also have had to make the code thread-safe, so I decided to skip that complexity. The code could also be more defensive, but I’m sure you get the picture.

The type name is defined in the app.config file like this:

<orderValidation 
  type="Ploeh.Samples.OrderModel.UnitTest.TrueOrderValidator,
        Ploeh.Samples.OrderModel.UnitTest" />
Obviously, CollectorProvider and ShipperProvider follow the same… blueprint.

This should be well-known to most .NET developers, so what’s wrong with this model?

Constrained Construction

In my book’s chapter on DI anti-patterns I describe the Constrained Construction anti-pattern. Basically it occurs every time there’s an implicit constraint on the constructor of an implementer. In the case of Providers the constraint is that each implementer must have a default constructor. In the example the culprit is this line of code:

var obj = Activator.CreateInstance(type);

This constrains any implementation of IOrderValidator to have a default constructor, which obviously means that the most fundamental DI pattern Constructor Injection is out of the question.

Variations of the Provider idiom is to supply an Initialize method with a context, but this creates a temporal coupling while still not enabling us to inject arbitrary Services into our implementations. I’m not going to repeat six pages of detailed description of Constrained Construction here, but the bottom line is that you can’t fix it - you have to refactor towards true DI - preferably Constructor Injection.

Hidden complexity

Providers hide the complexity of their implementations. This is not the same as encapsulation. Rather it’s a dishonest API and the problem is that it just postpones the moment when you discover how complex the implementation really is.

When you implement a client and use code like the following everything looks deceptively simple:

IOrderValidator validator = ValidatorProvider.Validator;

However, if this is the only line of code you write it will fail, but you will not notice until run-time. Check back to the implementation of the Validator property if you need to refresh the implementation: there’s a lot of things that can go wrong here:

The appropriate configuration section is not available in the app.config file.
The ValidatorTypeName is not provided, or is null, or is malformed.
The ValidatorTypeName is correctly formed, but the type in question cannot be located by Fusion.
The Type doesn’t have a default constructor. This is one of the other problems of Constrained Construction: it can’t be statically enforced because a constructor is not part of an abstraction’s API.
The created type doesn’t implement IOrderValidator.
I’m sure I even forgot a thing or two, but the above list is sufficient for me. None of these problems are caught by the compiler, so you don’t discover these issues until you run an integration test. So much for rapid feedback.

**I don’t like APIs that lie about their complexity.
Hiding complexity does not make an API easier to use; it makes it harder.
An API that hides necessary complexity makes it impossible to discover problems at compile time. It simply creates more friction.**

Lifetime management issues

A Provider exerts too much control over the instances it creates. This is a variation of the Control Freak anti-pattern (also from my book). In the current implementation the Validator property totally violates the Principle of least surprise since it returns a new instance every time you invoke the getter. I did this to keep the implementation simple (this is, after all, example code), but a more normal implementation would reuse the same instance every time.

However, reusing the same instance every time may be problematic in a multi-threaded context (such as a web application) because you’ll need to make sure that the implementation is thread-safe. Often, we’d much prefer to scope the lifetime of the Service to each HTTP request.

HTTP request scoping can be built into the Provider, but then it would only work in web applications. That’s not very flexible.

What’s even more problematic is that once we move away from the Singleton lifestyle (not to be confused with the Singleton design pattern) we may have a memory leak at hand, since the implementation may implement IDisposable. This can be solved by adding a Release method to each Provider, but now we are moving so far into DI Container territory that I find it far more reasonable to just use proper DI instead of trying to reinvent the wheel.

Furthermore, the fact that each Provider owns the lifetime of the Service it controls makes it impossible to share resources. What if the implementation we want to use implements several Role Interfaces each served up by a different Provider? We might want to use that common implementation to share or coordinate state across different Services, but that’s not possible because we can’t share an instance across multiple providers.

Even if we configure all Providers with the same concrete class, each will instantiate and serve its own separate instance.

Testability

The Control Freak also impacts testability. Since a Provider creates instances of interfaces based on XML configuration and Activator.CreateInstance, there’s no way to inject a dynamic mock.

It is possible to use hard-coded Test Doubles such as Stubs or Fakes because we can configure the XML with their type names, but even a Spy is problematic because we’ll rarely have an object reference to the Test Double.

In short, the Provider idiom is not a good approach to loose coupling. Although Microsoft uses it in some of their products, it only leads to problems, so there’s no reason to mimic it. Instead, use Constructor Injection to create loosely coupled components and wire them in the application’s Composition Root using the Register Resolve Release pattern.

基于深度学习的柑橘病害检测系统——YOLOv8 + UI界面 + 数据集 深度学习是机器学习的一种重要分支,它通过构建多层的神经网络(尤其是卷积神经网络CNN)来从大规模的数据中学习特征。近年来,深度学习特别是在计算机视觉领域取得了显著的进展,成为图像分类、目标检测、图像分割等任务的主要技术。对于农业病害检测问题,深度学习通过对大量带标签的病害图像进行训练,能够自动识别不同类型的病害,并判断病害的程度。通过图像中目标(病害区域)的边界框,可以快速定位病害区域,进一步分析其影响范围。 阅读详情

相关推荐

宇树G1双足机器人SLAM开发环境搭建实战指南

SLAM(同步定位与建图)是机器人自主导航的核心技术。在双足人形机器人平台上,由于运动模型复杂、机身晃动带来高频IMU噪声,SLAM开发对环境配置和依赖管理提出了更高要求。以宇树G1为例,系统阐述如何通过Ubuntu 20.04、ROS Noetic与Docker容器化方案构建可复现的SLAM开发环境。先介绍依赖分层管理与版本锁定原理,再深入catkin工作空间编译、传感器驱动集成、网络与多机通信配置等工程实践,最后提供常见问题排查与避坑指南。这套方法论不仅适用于G1,也可迁移至其他双足或轮式机器人平台,帮

weixin_32025789的博客 265

not DBmodule

Entrypoint main = apps/admin/main.js [Nest] 26849 - 2020-04-16 15:46:19 [NestFactory] Starting Nest application... [Nest] 26849 - 2020-04-16 15:46:19 [InstanceLoader] AppModule dependencies in...

周红伟讲AI 980

h5页面调用微信JS-SDK分享到微信好友或者朋友圈的配置

1.引入js &lt;script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"&gt;&lt;/script&gt; 2.在页面添加配置 &lt;script type="text/javascript"&gt; var url = location.href..

tiantiandashi的博客 2万+

There is no getter for property namedXXX(已解决

1.检查是否有getter方法,我是用lombok的@Data注解,会自动生成getter和setter还有toString方法,所以才被困了很久。2.实体类中定义的属性x必须得和#{x}完全一致,包括大小写(我就是这里出了错哈哈哈哈。昨天下班前一直被这个错误困扰,急着打球,今天才来解决这个问题。这个爆错意思是没有 getter 的属性。

m0_64704880的博客 4168

手把手教你玩转服务器芯片架构​专栏--​​3.5 实战案例:用SystemC搭建一个多核服务器芯片的NoC模型(含流量分配与延迟仿真)​

通过SystemC搭建多核NoC模型,可深入验证流量分配策略与延迟特性。实际工程中需结合FPGA原型验证(如Xilinx Alveo)进行时序收敛分析,并通过参数化设计适配不同服务器芯片需求。

MHD0815的博客 3043

攻克反光难题!YOLOv9工业缺陷检测实战:高反光件、微小划痕精准识别(附抗反光代码+产线数据)

文章摘要:本文针对不锈钢、铝合金等高反光工业件的缺陷检测难题,提出了一套“硬件抗反光+YOLOv9小目标增强”的解决方案。通过分析反光干扰(镜面/漫反射)和微小划痕(0.1mm级)两大核心问题,详细介绍了500万像素工业相机+偏振光源的硬件配置方案,以及基于偏振图像融合和超分辨率放大的预处理方法。最终实现误检率1.2%、微小划痕检出率99.3%的工业级检测效果,并提供了可落地的代码实现和车间实测数据。(148字)

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1039

出现The 'microsoft.jet.oledb.4.0' provider is not registered on the local machin 问题解决方案

出现The 'microsoft.jet.oledb.4.0' provider is not registered on the local machin 问题解决方案

LisenYang的专栏 1万+

YOLO创新点改进点的消融实验设计规范

YOLO改进的消融实验是一种重要的方法,用于评估和验证模型中不同组件的影响。在进行YOLO改进的消融实验时,我们可以选择一些可能的改进点,比如Backbone网络、Anchor框设计和损失函数设计,然后通过实验来分析它们对模型性能的影响。首先,我们需要确定实验设计。对于每个改进点,我们将设计多个实验组,并针对每个实验组训练模型并进行性能评估。这里以三个改进点为例进行说明:改进点1:Backbone网络 (改进点2:Anchor框设计 (改进点3:损失函数设计 (

crasher123的博客 2909

Mybatis匹配Mapper报no getter错误

mybatis 报 no getter错误

Mr.x的博客 1825

Qt QCustomPlot 图形库详解及使用

QCustomPlot 是一个开源的 Qt C++ 库,专门用于创建数据图表。易于集成到 Qt 项目中。支持多种图表类型,如折线图、散点图、条形图等。提供丰富的交互功能,如缩放、平移、选择和拖动。高度可定制,支持图形的各种样式设置。// 添加第一条曲线i < 101;++i) {// 设置曲线颜色// 添加第二条曲线i < 101;++i) {// 设置曲线颜色// 设置散点样式// 添加图例。

MusicScore的博客 764

优快云专栏限时活动!福利公告必读!

本人优快云付费专栏周排名27名专业博主,每周文章平均阅读量约7w以上!

FJN110的博客 3153

Mybatis异常 There is no getter for property...

Mybatis单个参数的if判断(针对异常:There is no getter for property…)------mybatis的内置对象 Mybatis 传单个参数,xml中直接用#{name}表达式取值是不会有问题的。 但是用&amp;lt;if test=&quot;name != null&quot;&amp;gt;去判断是否为空,这个时候就会报no getter...异常 // 下面是我直接网上摘抄的,原博客地...

温故而知新,可以为师矣。 3万+

Dify 第 19 篇 手把手教你开发 Dify 插件:从零实现一个时间工具

本文介绍了Dify平台的插件开发机制和流程。Dify支持多种插件类型,包括模型、工具、数据源等,可通过CLI工具快速开发插件。文章详细讲解了如何安装Dify CLI工具,并演示了从零开发一个获取系统时间插件的完整过程,包括项目初始化、文件解读和打包部署。通过该教程,开发者可以快速掌握Dify插件开发的核心要点,实现自定义功能扩展。

甘蓝的专栏 2445

The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.解决方案

    用C#读取Excel文件时,遇到了下图所示问题(The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.),一开始很困惑,明明上次读取文件成功了,怎么这次读取不到呢?        想了一下,上次也遇到过这个问题,寻着上次的做法,查找到了原因,如下图所示(原来的配置管理器是Any CPU,...

m0_37954004的博客 2万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Microsoft.ACE.OLEDB.12.0 provider is not registered (zz)

//z 2012-08-13 17:45:07 IS2120@优快云.T3388923946[T90,L1428,R36,V860] Q1 I have a Visual Studio 2008 solution with two projects (a Word-Template project and a VB.Net console application for te...

494

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SSM框架分页的时候报错 There is no getter for property named 'xx' in 'class java.lang.String

WARNING - @mbggenerated       This element is automatically generated by MyBatis Generator, do not modify.       This element was generated on Mon Mar 06 19:37:25 CST 2017.     -->            

beauty_魅影 1113

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

使用Mybatis遇到的there is no getter 异常

在使用mybatis的时候有时候会遇到一个问题就是明明参数是正确的,但是还是会提示There is no getter XXX这个异常,但是一般的解决办法是在mapper里面添加@Param注解来完成是别的,那么为什么会遇到这个问题呢? 以下为举例代码: Mapper层代码 public interface Pro1_Mapper { ...

weixin_34088583的博客 3041

mybaits错误解决:There is no getter for property named ... in 'class java.lang.String'

** mybaits错误解决:There is no getter for property named … in ‘class java.lang.String’ ** 在使用mybaitis传参数的时候,如果仅传入一个类型为String的参数,那么在 xml文件中应该使用_parameter来代替参数名。 也可以在mapper的接口中,给这个方法的参数加上@Param(value=“pare...

qq_38673289的博客 1749

nestjs+postgreSql实现单元测试

1、使用npm安装数据库连接模块 npm install --save pg 2、Nest 与数据库无关,允许与任何 SQL 或 NoSQL 数据库集成,先安装依赖包。 npm install --save @nestjs/typeorm typeorm mysql 3、

qq_42666043的博客 2226

Mybatis报错:There is no getter for property named 'xxx' in 'class xxx 的解决办法

在mybatis中遇到这样的报错,There is no getter for property named ‘xxx’ in 'class xxx ,这篇博客给出了解决办法。

扬帆向海的博客 17万+

oracle 64位服务器上报 OraOLEDB.Oracle provider is not registered on thelo cal machine

Failed to test connection. The ‘OraOLEDB.Oracle’ provider is not registered on the local machine. 本机安装的oracle11g的64位客户端,使用.net开发,使用oledb组件连接数据库,报错 The MSDAORA.1 provider is not registered on t

dacong的专栏 2761

64操作系统编译出错。The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine....

The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine. 今天装了64位win7,编译成功了,放在IIS里运行出错。The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine. 在此记录下来: T...

weixin_30814319的博客 193

Microsoft.ACE.OLEDB.12.0 provider is not registered解决方案

应用部署到服务器IIS上,提示Microsoft.ACE.OLEDB.12.0 provider is not registered,通过如下步骤解决: 1. 安装DataAccessEngine,下载地址: http://www.microsoft.com/downloads/details.aspx?FamilyID=7554F536-8C28-4598-9B72-EF94E038

种德养心 1万+

关于异常“The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine”的处理

我们在利用SqlBlukcopy技术倒2010 或者2007格式的文件到SqlServer 数据库的时候,会发生如下错误: 原因如下: 1.在用SQL SERVER 2005访问.xlsx文件(of

w36680130的博客 5367

there is no getter for property named解决方案

这个问题也是我昨天遇到的。 看问题描述我还以为是我VO对象(实体类)里面的没有对应的getter方法。一直检查将getter方法。检查半天也没找到原因。 后面去网上找,也没找到好的解决方案(我有看到相关的解决方案,然而觉得那些解决方案不够优雅。就没有去尝试) 问题的原因是什么?确实是实体类没有对应的get方法 上面这个是我修复了问题的示范。 我开始是 test = “city ==‘dl’” 因为我数据库表的字段叫city,但是我实体类里面的属性名字是cityEn。 如果我写city,属性里面确实没 ge

五更依旧朝花落的博客 9万+

如何解决 The'Microsoft.ACE.OLEDB.12.0' provider is not registered

、  安装AccessDatabaseEngine_X64,该版本是Access2010的开发程序包,下载地址如下:http://www.microsoft.com/zh-cn/download/details.aspx?id=13255,但调试仍然报同样的错误,问题没有解决,继续百度解决方案。 2 1、  在IIS中更改应用程序池设置。计算机右键[管理]——[服务和应用程序]——[Int

qq_32733803的博客 1万+
上一篇: 跨平台的格式
下一篇: ReentrantLock
我把葡萄酿成酒
博客等级 码龄12年 275粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值