坏味道——过大的类(Large Class)
特征
一个类含有过多字段、方法、代码行。
问题原因
类通常一开始很小,但是随着程序的增长而逐渐膨胀。
类似于过长方法,程序员通常觉得在一个现存类中添加新特性比创建一个新的类要容易。
解决方法
设计模式中有一条重要原则:职责单一原则。一个类应该只赋予它一个职责。如果它所承担的职责太多,就该考虑为它减减负。
- 如果过大类中的部分行为可以提炼到一个独立的组件中,可以使用
提炼类(Extract Class)
。 - 如果过大类中的部分行为可以用不同方式实现或使用于特殊场景,可以使用
提炼子类(Extract Subclass)
。 - 如果有必要为客户端提供一组操作和行为,可以使用
提炼接口(Extract Interface)
。 - 如果你的过大类是个GUI类,可能需要把数据和行为移到一个独立的领域对象去。你可能需要两边各保留一些重复数据,并保持两边同步。
复制被监视数据(Duplicate Observed Data)
可以告诉你怎么做。
收益
- 重构过大的类可以使程序员不必记住一个类中大量的属性。
- 在大多数情况下,分割过大的类可以避免代码和功能的重复。
重构方法说明
提炼类(Extract Class)
问题
当一个类职责不是单一的。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Class - Before.png)
解决
创建新的类,将用于实现某一功能的相关字段和方法放进去。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Class - After.png)
提炼子类(Extract Subclass)
问题
一个类中有些特性仅用于特定场景。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Subclass - Before.png)
解决
创建一个子类,并将用于特殊场景的特性置入其中。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Subclass - After.png)
提炼接口(Extract Interface)
问题
多个客户端使用一个类部分相同的方法。另一个场景是两个类中的部分方法相同。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Interface - Before.png)
解决
移动相同的部分方法到接口中。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Extract Interface - After.png)
复制被监视数据(Duplicate Observed Data)
问题
如果存储在类中的数据是负责GUI的。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Duplicate Observed Data - Before.png)
解决
一个比较好的方法是将负责GUI的数据放入一个独立的类,以确保GUI数据与域类之间的连接和同步。
![img](https://raw.githubusercontent.com/atlantis1024/JavaParty/master/images/%E7%BC%96%E7%A8%8B/%E9%AB%98%E6%95%88%E7%BC%96%E7%A8%8B/%E9%87%8D%E6%9E%84/large-class/Duplicate Observed Data - After.png)