泄露的封装

抽象通过公有接口(方法)暴露或泄露实现细节时,将导致这种坏味。需要注意的是,即使抽象不存在“不充分的封装”坏味,其公有接口也有可能泄露实现细节。

为什么不能泄露封装?

为实现有效封装,必须将抽象的接口(即抽象的内容)和实现(即抽象的方式)分离。为遵循隐藏原则,必须对客户程序隐藏抽象的实现方面。

如果通过公有接口暴露了实现细节(违反了隐藏原则)可能会造成:

  • 对实现进行修改时,可能会影响客户程序
  • 暴露的实现细节可能会让客户程序能够通过公有接口访问内部数据结构,进而有意或无意地损坏抽象的内部状态。

泄露的封装的潜在原因

不知道该隐藏哪些东西

开发人员通常会在无意之间泄露实现细节。

使用细粒度接口

类的公有接口直接提供了细粒度的方法,这些细粒度的方法通常会向客户程序暴露不必要的实现细节。更好的做法是在类的公有接口提供粗粒度的方法,在粗粒度方法内部使用细粒度的私有方法。

示例分析一

我们用程序来维护一个待办事项列表。在ToDoList类中,公有方法GetListEntries()返回对象存储的待办事项列表。

public class ToDoList
{private List<string> listEntries = new List<string>();public List<string> GetListEntries(){return listEntries;}public void AddListEntry(string entry){}
}

问题出在方法的返回类型上,它暴露了一个内部细节,ToDoList内部使用List来存储待办事项列表。

现在问题来了,如果待办事项列表程序主要执行插入和删除操作,那么选择使用List没啥问题;但是后来发现查找频率比修改频率高,那么使用HashTable可能更合适。然而GetListEntries()的返回类型是List,如果修改这个方法的返回类型,可能破坏依赖于这个方法的客户程序。如果要支持未来数据结构的变更,方法返回类型可以使用IEnumerable(C#中的集合类型都实现的接口类型),这样可以做到在不改变方法签名的条件下(里氏替换原则),替换存储待办事项列表的数据结构。

重构后的代码实现:

使用List数据结构:

public class ToDoList
{private List<string> listEntries = new List<string>();public IEnumerable GetListEntries(){return listEntries;}public void AddListEntry(string entry){}
}

使用Hashtable数据结构:

public class ToDoList
{private Hashtable listEntries = new Hashtable();public IEnumerable GetListEntries(){return listEntries;}public void AddListEntry(string entry){}
}

方法GetListEntries()存在另一个严重的问题是,它返回一个指向内部数据结构的引用,通过这个引用,客户程序可以绕过AddListEntry()方法直接修改数据结构。当然如果使用IEnumerable这个问题也就迎刃而解了,因为IEnumerable接口没有相应的针对于某一种数据集合的操作。

public interface IEnumerable
{//// 摘要://     返回循环访问集合的枚举数。//// 返回结果://     一个可用于循环访问集合的 System.Collections.IEnumerator 对象。[DispId(-4)]IEnumerator GetEnumerator();
}

示例分析二

假设显式图像包含4个步骤,这些步骤必须按照特定顺序执行,图形才可以正常显式。

现在在Image类中提供4个公有方法Load(),Process(),Validate(),Show()供客户程序使用,但是这样有一个很麻烦的问题是写客户程序的开发人员不一定会按照正确顺序调用方法使用(永远不要给客户选择的权利)。而且客户程序只是想要显式图像,我们为什么要向它们暴露4个内部步骤呢?这就是泄露的封装的潜在原因——使用细粒度接口。

public class Image
{public void Load(){}public void Process(){}public void Validate(){}public void Show(){}
}

要解决这个问题,可以让Image类只向客户程序暴露一个方法Display(),然后在这个方法内部按照特定顺序调用4个步骤方法。

public class Image
{private void Load(){}private void Process(){}private void Validate(){}private void Show(){}public void Display(){Load();Process();Validate();Show();}
}

总结

  1. 抽象通过公有接口暴露或泄露了实现细节时,客户程序可能直接依赖于实现细节吗,这种直接依赖性使得难以在不破坏既有客户代码的情况下对设计进行修改或扩展。
  2. 抽象泄露了内部数据结构时,抽象的完整性遭到了破坏。增加了代码运行阶段发生问题的可能性。

参考:《软件设计重构》



作者:喜欢天黑却怕鬼


来源:http://songwenjie.cnblogs.com/

声明:本文为博主学习感悟总结,水平有限,如果不当,欢迎指正。如果您认为还不错,不妨点击一下下方的【推荐】按钮,谢谢支持。转载与引用请注明出处。

转载于:https://www.cnblogs.com/songwenjie/p/8975354.html

【封装那些事】 泄露的封装相关推荐

  1. 【封装那些事】 缺失封装

    缺失封装 没有将实现变化封装在抽象和层次结构中时,将导致这种坏味. 表现形式通常如下: 客户程序与其需要的服务变种紧密耦合,每当需要支持新变种或修改既有变种时,都将影响客户程序. 每当需要在层次结构中 ...

  2. 【关于封装的那些事】 缺失封装 【关于封装的那些事】 泄露的封装 【关于封装的那些事】 不充分的封装 【图解数据结构】二叉查找树 【图解数据结构】 二叉树遍历...

    [关于封装的那些事] 缺失封装 目录 - 缺失封装 为什么不能缺失封装? 缺失封装潜在的原因 未意识到关注点会不断变化 混合关注点 幼稚的设计决策 示例分析一 示例分析二 总结 缺失封装 没有将实现变 ...

  3. WIN7封装教程2018系列(六)—封装

    第六系列是整个教程的重点,步骤必须细致谨慎考虑周全,尽量不要出错,我也反复封装了两三次才成功,并不是你们在教程里看到的一次就成功.我直接把正确封装步骤的截图,按顺序编辑好了,照着我的教程做就行了.封装 ...

  4. python中的封装调用_Python基础之封装

    一.什么是封装 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其 含义是其他程序无法调用. 要了解封装,离不开"私有化&qu ...

  5. sop4封装尺寸图_「光电封装」 有源光器件的结构和封装

    本文来源半导体封装 摘要: 本文对光发送器件.光接收器件以及光收发一体模块等有源光器件的封装类型.材料.结构和电特性等各个方面进行了研究,给出了详细研究结果. 1 有源光器件的分类 一般把能够实现光电 ...

  6. 芯片封装的作用以及常见封装技术

    芯片封装的作用 固定引脚系统 外部引脚系统通常使用两种不同的合金--铁镍合金及铜合金.前者用于高强度以及高稳定性的场合,后者具有导电性和导热性更好的优势. 物理性保护 物理性保护芯片通过封装以后可以免 ...

  7. bxl类型封装怎么转换为AD库封装

    bxl类型封装怎么转换为AD库封装 1.添加STM32F407ZGTx.bxl 文件 2.选择Altium Designer 3.点击 Export to Selected Tools 4.生成UL_ ...

  8. 封装的含义、封装的作用、如何封装、什么情况下封装?

    封装的含义.封装的作用.如何封装.什么情况下封装? 1.封装的含义:封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类).被封装的对象通常被称为抽象数据类型. ...

  9. bga封装扇出_扇出型封装为何这么火?

    原标题:扇出型封装为何这么火? --详解扇出型封装技术 2017年依然炙手可热的扇出型封装行业 新年伊始,两起先进封装行业的并购已经曝光:维易科(Veeco)签订了8.15亿美元收购优特(Ultrat ...

最新文章

  1. 2016网络安全***赛记录
  2. 4-8 string
  3. Leetcode 动态规划 Trapping Rain Water
  4. [Leedcode][JAVA][第9题][回文数][数学法]
  5. 开会浪费时间?高效会议的秘诀,是用数据支撑
  6. 设计模式系列之「工厂方法模式」
  7. java 反射api_个人编程学习网 - Java-操作反射其他的API
  8. React通用解决方案——浮层容器
  9. tomcat运行超时问题解决
  10. 龙泉寺贤超法师:用 AI 为古籍经书识别、断句、翻译
  11. js获取map对象的key和value
  12. WIN10 VS2019 编译Cyrus SASL
  13. excel表计算机实践操作,Excel电子表格计算机实践任务书.ppt
  14. r语言进行go富集分析_GO富集柱状图
  15. C# DataView常见操作
  16. Kafka服务器命令总结
  17. CSS中background-attachment的介绍和用法
  18. 模拟SPI进行TF卡操作+Fatfs文件系统移植
  19. 2019南京区块链论坛小结
  20. Tomcat探秘(1):Tomcat是什么?

热门文章

  1. DotDensityRenderer
  2. FZOJ2110: Star
  3. android菜单详解二:选项菜单
  4. 基于 Lerna 管理 packages 的 Monorepo 项目最佳实践
  5. Confluence 6 上传文件
  6. 将CSV文件存为HTML文件形式
  7. UED、UCD、UE、UI、交互设计概念
  8. codevs1018 单词接龙(DFS)
  9. .net web 点击链接在页面指定位置显示DIV的问题
  10. c# 整个工程(包括窗体工程)做成dll