什么是垫片?

Posted

技术标签:

【中文标题】什么是垫片?【英文标题】:What is a Shim? 【发布时间】:2011-01-08 03:18:52 【问题描述】:

Shim 的定义是什么?

【问题讨论】:

另见问题...***.com/questions/9512690/… 【参考方案1】:

通过卡通片简单解释垫片

垫片示例:

总结

shim 是一些代码,负责处理所询问的内容(通过“拦截”),而无需任何人对此更明智。

垫片示例

rbenv(一个简洁的 ruby​​ 工具)就是 shim 的一个例子。对 ruby​​ 命令的调用被“填充”。即当您运行bundle install 时,rbenv 会拦截该消息,并根据您正在运行的特定版本的 Ruby 重新路由它。如果这没有意义try this example,或者只是想想神仙母亲截取消息并提供适当的结果。

就是这样!

关于此示例的重要说明

注意:像大多数类比一样,这并不完美:通常 Ralph 会得到他想要的东西 - 但如何获得它的机制是 Ralph 不关心的。如果拉尔夫要狗粮,好的垫片会送狗粮。 另外,我不想涉及语义参数(也不想涉及不必要的细节/复杂性 - 例如四个设计模式的适配器帮派和类似的),所以我故意通过卡通简化为一般概念,以便您可以快速/轻松地获得要点 - 这种方法有利有弊 - 如果您更喜欢百科全书式的定义,那么也许可以考虑Wikipedia entry on shims。

【讨论】:

【参考方案2】:

根据其定义,从技术上讲,***中定义的“shim”一词将被归类为“结构”设计模式。许多类型的“结构”设计模式在(有些人会说事实上的)面向对象软件设计模式参考"Design Patterns, Elements of Reusable Object-Oriented Software" 更广为人知的"Gang of Four" 中进行了非常清楚的描述。

"Gang of Four" 文本概述了至少 3 种成熟的模式,称为“代理”、“适配器”和“外观”,它们都提供“垫片”类型的功能。在大多数领域中,经常会使用或漏用不同的首字母缩写词来表示相同的词根概念,这会导致人们感到困惑。使用“shim”一词来描述更具体的“结构”设计模式"Proxy"、"Adapter" 和"Facade" 无疑是这种情况的一个明显例子。 “shim”只是更具体的“结构”模式“代理”、“适配器”、“外观”和可能的其他类型的更通用术语。

【讨论】:

这个答案表明 shim 是一种设计模式(众多设计模式之一),命名了一些类似的设计模式,并且与人们如何被不同的首字母缩写词混淆的切线相吻合。但它实际上并没有回答垫片是什么、它的作用或如何使用垫片的原始问题。【参考方案3】:

根据微软的文章"Demystifying Shims":

这是一个基于英语单词 shim 的隐喻,它是 用于描述一块木头或金属的工程术语 插入两个对象之间以使它们更好地结合在一起。在 计算机编程,垫片是一个透明的小型库 拦截 API,更改传递的参数,处理 操作本身,或将操作重定向到别处。垫片也可以 用于在与它们不同的软件平台上运行程序 为。

因此,shim 是任何代码库的通用术语,它充当中间人并部分或完全改变程序的行为或操作。就像真正的中间人一样,它可以影响传递给该程序的数据,或影响从该程序返回的数据。

Windows API 就是一个例子:

应用程序通常不知道请求将发送到 shim DLL 而不是 Windows 本身,并且 Windows 不知道 请求来自应用程序以外的其他来源(因为 shim DLL 只是应用程序进程中的另一个 DLL)。

因此,制作“shim 三明治”的“面包”的两个程序应该无法区分与对应程序对话和与 shim 对话。

使用垫片有哪些优缺点?

再次,来自文章:

您可以在不访问源代码或不访问源代码的情况下修复应用程序 完全改变它们。您需要支付最少的额外费用 管理开销......你可以修复一个 合理数量的应用程序这种方式。不利的一面是支撑 大多数供应商不支持垫片应用程序。你不能修复每一个 使用垫片的应用程序。大多数人通常认为垫片用于 供应商停业的应用程序,软件不是 战略性足以需要支持,或者他们只是想购买一些 时间。

【讨论】:

【参考方案4】:

至于单词的来源,引用 Apple 的 Dictionary 小部件

noun
   a washer or thin strip of material used to align parts, 
   make them fit, or reduce wear.

verb ( shimmed, shimming) [ trans. ]
   wedge (something) or fill up (a space) with a shim.

ORIGIN early 18th cent.: of unknown origin

这似乎非常适合网页设计师使用该术语的方式。

【讨论】:

【参考方案5】:

垫片用于 .net 4.5 Microsoft Fakes 框架to isolate your application from other assemblies for unit testing。 Shims 将调用转移到您在测试中编写的特定方法的代码

【讨论】:

【参考方案6】:

另一个垫片示例

当我还是个孩子的时候,我的祖母住在同一个城镇。那是一个小镇。大家都认识。

我曾经给她写信:

To:   Grand Ma
From: Ben

然后把它投进邮箱…………那些用来寄给她的信,一定不会失败。

我不知道也不关心它是怎么发生的。

问:这就引出了一个问题:信件是如何送达的?

答:这很简单:消息被填充。因为它是一个小镇,邮局的那个人知道这封信是谁写的(来自 Woop Woop 的 Ben),也知道奶奶的地址,因此更改并填充地址以便消息可以正确交付给她。

# shimmed msg thanks to Post Office operator
To:   Mrs Ammama Kutty, 1 PA Avenue.... 
From: Ben

这是相同的基本概念,但适用于代码。你发信息。该消息被拦截,结果如预期。那是一个垫片。

【讨论】:

【参考方案7】:

正如我们在此处的许多响应中看到的那样,垫片是一种适配器,它在 API 级别提供功能,不一定是该 API 的一部分。这个帖子有很多好的和完整的响应,所以我不进一步扩展定义。

不过,我想我可以添加一个很好的例子,那就是 javascript ES5 Shim (https://github.com/es-shims/es5-shim):

在过去的几年里,Javascript 有了很大的发展,在语言规范的许多其他变化中,许多新方法被添加到其核心对象中。

例如,在 ES2015 规范(又名 ES5)中,find 方法已添加到 Array 原型中。因此,假设您正在使用该规范之前的 JavaScript 引擎运行您的代码(例如:Node 0.12),该引擎尚不提供该方法。通过加载 ES5 shim,这些新方法将被添加到 Array 原型中,即使您没有在较新的 JavaScript 规范上运行,也可以使用它们。

您可能会问:为什么有人会这样做而不是将环境升级到较新的版本(比如 Node 8)?

有很多真实案例场景表明这种方法是有意义的。一个很好的例子:

假设您有一个在旧环境中运行的旧系统,您需要使用这些新方法来实现/修复某个功能。您的环境升级仍在进行中,因为存在需要大量代码更改和测试(关键组件)的兼容性问题。

在此示例中,您可以尝试制作您自己的此类功能版本,但这会使您的代码更难阅读、更复杂、可能会引入新错误,并且需要大量额外测试才能涵盖您想要的功能知道它将在下一个版本中提供。

相反,您可以使用此填充程序并利用这些新方法,利用此修复/功能将在升级后兼容的事实,因为您已经在使用已知在下一个规范中可用的方法.还有一个额外的原因:由于这些方法是下一个语言规范的原生方法,因此它们很有可能比您尝试制作自己的版本时可以完成的任何实现都运行得更快。

另一个受欢迎的实际场景是在浏览器级别。假设您需要支持旧浏览器并希望利用这些新功能。 Javascript 是一种允许您在其核心对象中添加/修改方法的语言(例如向 Array 原型添加方法),并且那些 shim 库足够聪明,只有在当前实现缺少这些方法时才添加这些方法。

PS: 1) 您将看到与这些 Javascript 垫片相​​关的术语“Polyfill”。 Polyfill 是一种更专业的填充程序,用于在不同的浏览器级别规范中提供前向兼容性。顺便说一下,我上面的例子就是指这样的例子。

2) 垫片不限于此示例(添加将在未来版本中可用的功能)。也有不同的用例被视为 shim。

3) 如果您对这个特定的 polyfill 是如何实现的感到好奇,您可以打开 Javascript Array.find 规范并滚动到页面末尾,您会在其中找到该方法的规范实现。

【讨论】:

【参考方案8】:

SHIM 是对所有服务进行的另一级安全检查,以保护上游系统。 SHIM 服务器根据请求中传递的用户凭据(SOAP / RESTFUL)使用标头用户凭据验证每个传入请求。

【讨论】:

以上是关于什么是垫片?的主要内容,如果未能解决你的问题,请参考以下文章

垫片和 polyfill 有啥区别?

在不使用垫片的情况下定位视图底部

在 DIV 上实现跨浏览器兼容性的良好“背景大小:覆盖”后备/垫片/技巧?

RequireJS - 垫片为CoffeeScript的脚本

如何从巧克力垫片中获取二进制路径?

sh Ansible角色测试垫片。