重构笔记——提炼类

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43059759

        在上一篇文章中介绍了“搬移字段”。本文将介绍“提炼类”这种重构手法。

        下面让我们来学习这种重构手法吧。

开门见山

        发现:某个类做了应该由两个类做的事。

解决:建立一个新类,将相关的字段和函数从旧类搬移到新类。

动机

我们或多或少听过这样的教诲:一个类应该是一个清楚的抽象,处理一些明确的责任。但是,在实际工作中,类会不断成长扩展。你会在这儿加一些功能,在那儿加入一些数据。 当给类添加新责任时,就会觉得不值得为这项责任分理出一个单独的类。于是,随着责任的不断增加,这个类会变得过分复杂。很快,类就会变成一团乱麻,继而你就越发不想管理。

这样的类往往含有大量函数和数据,往往太大而不易理解。此时,就需考虑哪些部分是可以分离出去的,并将它们分离到一个单独的类中。如果某些数据和某些函数总是一起出现,某些数据经常同时变化甚至彼此相依,这就说明应该将其分离处理。一个比较有用的测试就是问问自己:如果搬移了某些字段和函数,会发生什么事情?其它字段和函数是否会变得无意义?

还有一个值得注意的地方是类的子类化方式。如果发现子类化只影响类的部分特性,或如果发现某些特性需要以一种方式来子类化,而另一些特性则需要以另一种方式子类化,则意味着需要分解原来的类。

做法

(1)决定如何分解类所负的责任。

(2)建立一个新的类,用以表现从旧类中分离出来的责任(如果旧类剩余的责任与旧类名不符,则为旧类更名)。

(3)建立从旧类访问新类的连接关系。(有可能需要一个双向连接,但是在真正需要它之前,不要建立“从新类通往旧类”的连接)

(4)对于待搬移的每个字段,运用“搬移字段”将其搬移。

(5)每次搬移后,都进行编译、测试。

(6)使用“搬移方法”将必要函数搬移到新类。先搬移较底层函数(即“被其它函数调用”多余“调用其它函数”的函数),然后搬移高层函数。

(7)每次搬移后,都进行编译、测试。

(8)检查,精简每个类的接口。(如果你建立了双向连接,检查是否应该将其改为单向连接)

(9)决定是否公开新类,如果确定公开它,就要决定让它成为引用对象还是不可变对象。

示例

我们从一个简单的Person类开始:

	// 提炼类
	class Person {
		private String _name;
		private String _officeAreaCode;
		private String _officeNumber;

		public String get_name() {
			return _name;
		}

		public String getTelephoneNumber() {
			return ("(" + _officeAreaCode + ")" + _officeNumber);
		}

		public String get_officeAreaCode() {
			return _officeAreaCode;
		}

		public void set_officeAreaCode(String areaCode) {
			_officeAreaCode = areaCode;
		}

		public String get_officeNumber() {
			return _officeNumber;
		}

		public void set_officeNumber(String number) {
			_officeNumber = number;
		}
	}

在这个例子中,可以将与电话号码相关的行为分离到一个独立类中。首先需要定义一个TelephoneNumber类来表示“电话号码”这个概念:

	class TelephoneNumber {

	}

然后建立从Person到TelephoneNumber的连接:

	class Person {
		//...
		private TelephoneNumber _officeTelephone = new TelephoneNumber();
	}

现在,可以运用“搬移字段”手法移动一个字段:

	class TelephoneNumber {
		private String _areaCode;

		public String get_AreaCode() {
			return _areaCode;
		}

		public void set_AreaCode(String areaCode) {
			_areaCode = areaCode;
		}
	}

	class Person {
		//......
		private TelephoneNumber _officeTelephone = new TelephoneNumber();

		public String getTelephoneNumber() {
			return ("(" + get_officeAreaCode() + ")" + _officeNumber);
		}

		public String get_officeAreaCode() {
			return _officeTelephone.get_AreaCode();
		}

		public void set_officeAreaCode(String areaCode) {
			_officeTelephone.set_AreaCode(areaCode);
		}
	}

然后可以移动其它的字段,并运用“搬移函数”手法将相关函数移动到TelephoneNumber类中:

	class Person {
		//......
		private TelephoneNumber _officeTelephone = new TelephoneNumber();
		private String _name;

		public String get_name() {
			return _name;
		}

		public String getTelephoneNumber() {
			return _officeTelephone.getTelephoneNumber();
		}

		public TelephoneNumber getOfficeTelephone() {
			return _officeTelephone;
		}
	}

	class TelephoneNumber {
		private String _areaCode;
		private String _number;

		public String get_AreaCode() {
			return _areaCode;
		}

		public String getTelephoneNumber() {
			return ("(" + _areaCode + ")" + _number);
		}

		public void set_AreaCode(String areaCode) {
			_areaCode = areaCode;
		}

		public String getNumber() {
			return _number;
		}

		public void setNumber(String number) {
			_number = number;
		}
	}

下一步要决定是否对用户公开这个新类?可以将Person中与电话号码相关的函数委托至TelephoneNumber,从而完全隐藏这个新类;也可以直接将它对用户公开。也可以将它公开给部分用户(位于同一个包中的用户),而不公开给其它用户。

本文主要介绍了重构手法——提炼类。该重构手法在开发的过程中也会经常性地用到,想想平时在开发的过程中,将一个类中的某些特性移到另一个新的类中,将它们的职责分的清清楚楚,这样也便于开发可后期的维护。提炼类是改善并发程序的一种常用技术。因为它使得为提炼后的两个类可以分别加锁。但是如果不需要同是锁定两个对象,就不必这样做。这里也会面临事务的问题,当确保两个对象被同时锁定。这样也会存在一定的危险性。

最后,希望本文对你有所帮助。有问题可以留言,谢谢。(PS:下一篇将介绍重构笔记——将类内联化)

重构笔记文章

重构笔记——入门篇

重构笔记——代码的坏味道(上

重构笔记——代码的坏味道(下)

重构笔记——构筑测试体

重构笔记——提炼函数

重构笔记——内联函数

重构笔记——内联临时变量

重构笔记——以查询取代临时变量

重构笔记——引入解释性变量

重构笔记——分解临时变量

重构笔记——移除对参数的赋值

重构笔记——搬移函数

重构笔记——搬移字段

重构笔记——提炼类

时间: 2024-10-19 02:12:28

重构笔记——提炼类的相关文章

重构笔记——将类内联化

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43159817         在上一篇文章中介绍了"提炼类".本文将介绍"将类内联化"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:某个类并没有做太多的事情. 解决:将这个类的所有特性搬移到另一个类中,然后移除原类. 动机 "将类内联化"正好与"

重构笔记——提炼函数

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42214393         在前面的三篇文章中介绍了重构入门篇.代码的坏味道(上).代码的坏味道(下).本文将正式开启重构之旅.从本文开始在后续的文章中会陆续介绍92种重构手法,每一种重构手法都会对应于一种代码坏味道.在介绍的过程中,每一种重构手法也将对应一篇文章,可能有的重构手法比较简短,但是为了便于整理还是单独将其列为一篇.(PS:不管怎样,我都会坚

重构笔记——隐藏“委托关系”

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43769929         在上一篇文章中介绍了"将类内联化".本文将介绍"隐藏委托关系"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:客户通过一个委托关系来调用另一个对象. 解决:在服务类上建立客户所需的所有函数,用以隐藏委托关系. 动机 我们都知道,"封装&q

重构笔记——搬移字段

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42780243         在上一篇文章中介绍了"搬移函数".本文将介绍"搬移字段"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:程序中某个字段被其所驻类之外的另一个类更多地用到. 解决:在目标类新建一个字段,修改原字段的所有用户,令它们改用新字段. 动机 在类之间移动状态

重构笔记——引入本地扩展

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/44958839         在上一篇文章中介绍了"引入外加函数".本文将介绍"引入本地扩展"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:你需要为服务类提供一些额外函数,但你无法修改这个类. 解决:建立一个新类,使它包含这些额外函数.让这个扩展品成为源类的子类或者包装类.

重构笔记——构筑测试体系

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42167015 作为一名程序员,不知你是否在开发过程中也很少甚至不写测试程序,可能大多数人觉得这很正常,其实从个人角度来看也很正常,因为毕竟有测试人员专门进行测试的嘛!但是,如果能够认真观察程序员把最多时间耗在哪里,你就会发现,编写代码其实只占非常小的一部分.有些时间用来决定下一步干什么,另一些时间花在设计上,最多的时间则是用来调试.我敢肯定每一位读者都还记

重构笔记——搬移函数

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42679983         我们都知道,类往往因为承担过多的责任而变得臃肿不堪.这种情况下,一般会使用"提炼类"这种手法将一部分责任分离出去.如果一个类变得"不负责任",一般会使用"内联类"这种手法将它融入另一个类.如果一个类使用了另一个类,一般会运用"隐藏委托关系"手法将这种关系隐藏

重构笔记——分解临时变量

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42463871         在上一篇文章中介绍了"重构笔记--引入解释性变量".本文将介绍"分解临时变量"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果. 解决:针对每次赋值,创造一个独立.对应的

重构笔记——移除对参数的赋值

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42497857         在上一篇文章中介绍了"分解临时变值".本文将介绍"移除对参数的赋值"这种重构手法.         下面让我们来学习这种重构手法吧. 开门见山         发现:代码对一个参数进行赋值. 解决:以一个临时变量取代该参数的位置. //重构前 int dicount(int inputVal, i