写点什么

【关于封装的那些事】 缺失封装,2021 年腾讯 Java 高级面试题及答案

用户头像
极客good
关注
发布于: 刚刚

缺失封装


=================================================================


没有将实现变化封装在抽象和层次结构中时,将导致这种坏味。


表现形式通常如下:


  • 客户程序与其需要的服务变种紧密耦合,每当需要支持新变种或修改既有变种时,都将影响客户程序。

  • 每当需要在层次结构中支持新变种时,都添加了大量不必要的类,这增加了设计的复杂度。


为什么不能缺失封装?




开闭原则(OCP)指出,类型应对扩展开放,对修改关闭。也就是说应该通过扩展(而不是修改)来改变类型的行为。没有在类型或层次结构中封装实现变化时,便违反了 OCP。


缺失封装潜在的原因



未意识到关注点会不断变化

没有预测到关注点可能发生变化,进而没有在设计中正确封装这些关注点。

混合关注点

将彼此独立的各个关注点聚合在一个层次结构中,而不是分开时,如果关注点发生变化,可能导致类的数量呈爆炸式增长。

幼稚的设计决策

采用过于简单的方法,如为每种变化组合创建一个类时,可能导致设计无谓的复杂。


示例分析一




假设有一个 Entryption 类,它需要使用加密算法对数据进行加密。可供选择的加密算法有很多,包括 DES(数据加密标准)、AES(高级加密标准)、TDES(三重数据加密标准)等。Entryption 类使用 DES 算法对数据进行加密。


public class Encryption


{


/// <summary>


/// 使用 DES 算法进行加密


/// </summary>


public void Encrypt() {


// 使用 DES 算法进行加密


}


}


假设出现了新需求,要求使用 AES 算法对数据进行加密。


最差的方案出现了:


public class Encryption


{


/// <summary>


/// 使用 DES 算法进行加密


/// </summary>


public void EncryptUsingDES() {


// 使用 DES 算法进行加密


}


/// <summary>


/// 使用 AES 算法进行加密


/// </summary>


public void EncryptUsingAES() {


// 使用 AES 算法进行加密


}


}


这种方案有很多不尽如人意的地方:


  • Encryption 类变得更大、更难以维护,因为它实现了多种加密算法,但是每次只使用一种。

  • 难以添加新算法以及修改既有算法,因为加密算法是 Encryption 类不可分割的部分。

  • 加密算法向 Encryption 类提供服务,但是与 Encryption 类紧紧耦合在一起,无法在其它地方重用。


不满意就重构,首先使用继承进行重构,会有 2 种方案可以选择:


选择 1:


让 Encryption 类根据需求继承 AESEncryptionAlgorithm 或 DESEncryptionAlgorithm 类,并提供方法 Encrypt()。这种方案带来的问题是 Encryption 类在编译阶段就将关联到特定的加密算法,更严重的是类之间的关系并不是 is-a 关系。


/// <summary>


/// AES 算法加密类


/// </summary>


public class AESEncryptionAlgorithm


{


/// <summary>


/// 使用 AES 算法进行加密


/// </summary>


public void EncryptUsingAES() {


// 使用 AES 算法进行加密


}


}


/// <summary>


/// DES 算法加密类


/// </summary>


public class DESEncryptionAlgorithm


{


/// <summary>


/// 使用 DES 算法进行加密


/// </summary>


public void EncryptUsingDES()


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


{


// 使用 DES 算法进行加密


}


}


public class Encryption: AESEncryptionAlgorithm


{


/// <summary>


/// 使用算法进行加密


/// </summary>


public void Encrypt() {


EncryptUsingAES();


}


}


选择 2:


创建子类 AESEncryption 和 DESEncryption,它们都扩展了 Encryption 类,并分别包含加密算法 AES 和 DES 的实现。客户程序可创建 Encryption 的引用,这些引用指向特定子类的对象。通过添加新的子类,很容易支持新的加密算法。但是这种方案的问题是 AESEncryption 和 DESEncryption 将继承 Encryption 类的其它方法,降低了加密算法的可重用性。


public abstract class Encryption


{


/// <summary>


/// 使用算法进行加密


/// </summary>


public abstract void Encrypt();


}


/// <summary>


/// AES 算法加密类


/// </summary>


public class AESEncryption : Encryption


{


/// <summary>


/// 使用 AES 算法进行加密


/// </summary>


public override void Encrypt() {

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
【关于封装的那些事】 缺失封装,2021年腾讯Java高级面试题及答案