`

第六章 重新组织函数

 
阅读更多

 

一、Extrat Method(提炼函数)

定义:将这段代码放进一个独立函数中,并让函数名称解释该函数的用途。

自我理解:就是将一个复杂的函数或者过长的函数分解成独立的小函数。

例子:

 

void printOwing(){
		Enumeration e =_orders.elements();
		double outstanding = 0.0;
		
		//print banner
		System.out.println("*********************");
		System.out.println("******Banner*********");
		System.out.println("*********************");
		
		//calucate outstanding
		while (e.hasMoreElements()) {
			Order each = (Order) e.nextElement();
			outstanding += each.getAmount();			
		}
		
		//print details
		System.out.println("name:" + _name);
		System.out.println("amount" + outstanding);
	}
  
void printOwing(){
		printBanner();
		double outstanding = calucateOutstanding(12);
		printDetails();
	}
	
	void printDetails(double ountstanding){
		System.out.println("name:" + _name);
		System.out.println("amount" + outstanding);
	}
	
	void calucateOutstanding(double initValue){
		double result = initValue;
		Enumeration e =_orders.elements();
		while (e.hasMoreElements()) {
			Order each = (Order) e.nextElement();
			result += each.getAmount();			
		}
		return relust;
	}
	
	void printBanner(){
		//print banner
		System.out.println("*********************");
		System.out.println("******Banner*********");
		System.out.println("*********************");
	}
 
 

 

当看见一个过长的函数或者一段需要注释才能让人理解的用途的代码,我就会将这段代码放进一个独立的函数中。

优点:

1.每个函数的粒度都很小,那么函数的复用机会会很大。

2.这会使高层函数读起来就想一系列注释。

3.如果函数都是细粒度,那么函数的覆写也会更容易一些。

注意:

1.创造一个函数,根据这个函数的意图来对它进行命名(以它“做什么”来命名,而不是以它“怎么做”命名)。

2.注意函数的临时变量的变化。

3.函数名称应该清晰,能够清楚表达该函数具体是做什么。

 

 

二、Inline Method(内联函数)

定义:一个函数本体与名称清楚易懂,在函数调用点插入函数本体,然后移除该函数。

自我理解:如果啊函数内部的代码和函数名称同样清晰易读,那就去掉这个函数,虽然间接性可能带来帮助,但是非必要的间接性总是让人不舒服。通常函数主体为一行代码。

 

 

 

	int getRating(){
		return (moreThanFiveLateDeliveries())?2:1;
	}
	
	boolean moreThanFiveLateDeliveries(){
		return _numberOflateDeliveries>5;
	}
 

 

 

	int getRating(){
		return (_numberOflateDeliveries>5)?2:1;
	}
 

 

 

注意:

1.如果使用太多的间接层,使得系统中所有的函数似乎只是对另一个函数的简单委托,会被这些委托动作搞的晕头转向,那么请使用本重构。

 

 

 

三、Inline Temp(内联变量)

定义:有一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构的手法。将所有对该变量的引用动作,替换为对它赋值的那个表达式。

自我理解:一般来说,这个临时变量不会有任何的危害,但是如果妨害了其他的重构方法,例如抽取函数,那么就将它内联。

 

		double basePrice = anOrder.basePrice();
		return (basePrice > 1000);
 

 

 

return (anOrder.basePrice() > 1000);
 

 

注意:

1.如果临时变量过多地方被引用,可以使用final进行确定这个变量是否只被赋值一次。

 

 

 

四、Replace Temp with Query(以查询取代临时变量)

定义:你的程序以一个临时 变量保存某一表达式的运算结构。将这个表达式提炼到一个独立的函数中。将这个临时变量的所有引用点替换为新函数的调用。此后,新函数就可以被其他函数使用。

自我理解:这个重构一般是抽取函数之前必不可少的一步,局部变量会使代码难以被提炼,所以你应该尽可能把他们替换为查询式。

 

 

 

double getPrice(){
		int basePrice = _quatity*_itemPrice;
		double discountFactor;
		if(basePrice>1000) discountFactor = 0.95;
		else discountFactor = 0.98;
		return basePrice * discountFactor;
	}
 

 

 

 

double getPrice(){
		return getBasePrice() * getDisCountFactor();
	}
	
	int getBasePrice(){
		return _quatity*_itemPrice;
	}
	
	double getDisCountFactor(){
		if(getBasePrice()>1000) return  0.95;
		else return 0.98;
	}
 

 

 

注意:

1.我们常常使用临时变量保存循环中累加信息,在这种情况下,我们经常将这个循环都可以被提炼一个独立函数。如果一个循环累加几个值,建议对每个值见一个函数进行累加,性能先暂时不考虑。

 

 

五、Introduce Explaining Variable(引入解释性变量)

定义:有一个复杂的表达式,将该复杂的表达式(或者其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。

自我理解:表达式有时候可能非常复杂而难以阅读,临时变量可以帮主你将表达式分解为比较容易管理和理解的形式。

 

 

double price(){
		//price is base price - quantity discount + shipping
		return _quantity * _itemPrice
		-Math.max(0,_quantity-500)*_itemPrice*0.05
		+Math.min(_quantity*_itemPrice*0.1,100);
	}
  

 

 

double price(){
		final double basePrice = _quantity * _itemPrice;
		final double quantityDiscount = Math.max(0,_quantity-500)*_itemPrice*0.05;
		final double shipping = Math.min(basePrice*0.1,100);
		return basePrice - quantityDiscount + shipping;
	}

 

 也可以提供抽取方法的重构:

 

double price(){
		return getBasePrice() - getQuantityDiscount() + getShipping(); 
	}
	
	double getBasePrice(){
		return _quantity * _itemPrice;
	}
	
	double getQuantityDiscount(){
		return Math.max(0,_quantity-500)*_itemPrice*0.05;
	}
	
	double getShipping(){
		return Math.min(getBasePrice()*0.1,100);
	}
 

 

 

 

注意:

1.这个重构好像与"以查询取代临时变量"重构冲突,这两个方法可以同时使用,可以对程序进行更好的理解,不过个人推荐抽取方法此重构,因为临时变量拥有很大的局限性,只能在方法内部使用,函数在对象的生命周期都可以进行使用,也可以提供外部使用。

 

 

六、Split Temporary Variable(分解临时变量)

定义:程序有某个临时变量被赋值超过一次,它既不是循环变量,也不是被用于收集计算结果。针对每次赋值,创造一个独立、对应的临时变量

自我理解:如果临时变量被赋值超过一次,就意味在函数中承担了一个以上的责任,如果临时变量承担多个责任,它就应该被分节成多个临时变量,每个变量只承担一个责任。同一个临时变量承担两件不同的事情。

 

 

double getDistanceTravelled(int time){
		double result;
		double acc = _primaryForce / _mass;
		int primaryTime = Math.min(time,_delay);
		result =  0.5 * acc * primaryTime *primaryTime;
		int secondaryTime = time - _delay;
		if(secondaryTime > 0){
			double primaryVel = acc * _delay;
			acc = (_primaryForce + _secondaryForce) / _mass;
			result += primaryVel *_secondaryForce + 0.5 * acc *secondaryTime * secondaryTime;
		}
		return result;
	}
 

 

 

double getDistanceTravelled(int time){
		return getPrimaryDistanceTravelled(time) + getSecondDistanceTravelled(time);
	}
	
	double getPrimaryDistanceTravelled(int time){
		double acc = _primaryForce / _mass;
		int primaryTime = Math.min(time,_delay);
		return 0.5 * acc * primaryTime *primaryTime;
	}
	
	double getSecondDistanceTravelled(int time){
		double firstAcc = _primaryForce / _mass;
		int secondaryTime = time - _delay;
		if(secondaryTime > 0){
			double primaryVel = firstAcc * _delay;
			double secondAcc = (_primaryForce + _secondaryForce) / _mass;
			return  primaryVel *_secondaryForce + 0.5 * secondAcc *secondaryTime * secondaryTime;
		}
		return 0d;
	}
  注意:

 

1.结果集变量和循环变量可以进行重新赋值。

 

七、Remove Assignments to Parameters(移除对参数的赋值)

定义:代码对一个参数进行 赋值。以一个临时变量取代该参数的位置。

自我理解:“对参数赋值”意味改变参数,会造成职责不明。

 

 

int discount(int inputVal,int quantity, int yearToDate)(){
		if(inputVal > 50) inputVal -= 2;
		if(quantity >100) inputVal -= 1;
		if(yearToDate > 100000) inputVal -=4;
		return inputVal;
	}
  

 

 

int discount(int inputVal,int quantity, int yearToDate)(){
		int result = inputVal;
		if(inputVal > 50) result -= 2;
		if(quantity >100) result -= 1;
		if(yearToDate > 100000) result -=4;
		return result;
	}
 

 

 

注意:

1.如果是对象传值,因此可以修改参数对象的内部状态,但对参数对象重新赋值是没有意义。

 

八、Replace Method with Method OBject(以函数对象取代函数)

定义:有一个大型的函数,其中对局部变量的使用使你无法采用Extract Method。将这个函数放进 单独对象中,如此一来局部变量就成了对象内的字段。然后可以在同一个对象中将这个大象函数分解成为多个小型函数。

自我理解:如果一个函数之中局部变量泛滥成灾,那么分解 必定十分困难。在建立方法对象时,需要针对原函数的每个临时变量和每个参数,在新类中建立了一个对应的字段进行保护。

 

	//Class Accout
	int gamma(int inputVal, int quantity,int yearToDate){
		int importtantValue1 = (inputVal * quantity) + delta();
		int importtantValue2 = (inputVal * yearToDate) + 100;
		if((yearToDate - importtantValue1) > 100)
			importtantValue2 -= 20;
		int importtantValue3 = importtantValue2 * 7;
		//and so on.
		return importtantValue3 - 2 * importtantValue1;
	}
 

 

 

class Gamma{
	private final Account _account;
	private int inputVal;
	private int quantity;
	private int yearToDate; 
	private int importtantValue1;
	private int importtantValue2;
	private int importtantValue3;
	
	public Gamma(Accout source,int inputValArg,int quantityArg,input yearToDateArg){
		_accout = source;
		inputVal = inputValArg;
		quantity = quantityArg;
		yearToDate = yearToDateArg;
	}
	
	
	int compute(){
		importtantValue1 = (inputVal * quantity) + _account.delta();
		importtantValue2 = (inputVal * yearToDate) + 100;
		importantThing();
		importtantValue3 = importtantValue2 * 7;
		//and so on
		return importtantValue3 - 2 * importtantValue1;
	}
	
	void importtantThing(){
		if((yearToDate-importtantValue1) > 100)
			importtantValue2 -= 20;
	}
}
 注意:

 

1.由于我们将局部变量我们就可以顺利将大函数分解一个一个小函数,也方便我们去分析这个函数具体的作用与流程,这个重构特别对大型的重构方法有特别效果。

2.要将本对象当一个构造参数传入方法函数。

 

 

九、Substitute Algorithm(替换算法)

定义:你想要某个算法替换为另一个清晰的算法。将函数本体替换为另一个算法。

自我理解:有些算法是陈旧复杂的,例如循环的遍历等等。

 

String foundPerson(String[] people){
		for (int i = 0; i < people.length; i++) {
			if (people[i].equals("Don")) {
				return "Don";
			}
			if (people[i].equals("John")) {
				return "John";
			}
			if (people[i].equals("Kent")) {
				return "Kent";
			}
		}
	}
 

 

 

 

String foundPerson(String[] people){
		List cadidates = Arrays.asList(new String[]{"Don","John","Kent"});
		for (int i = 0; i < people.length; i++) {
			if (cadidates.contains(people[i])) {
				return people[i];
			}
		}
		return "";
	}
 

 

  • 大小: 1.4 KB
分享到:
评论

相关推荐

    第6章 函数

    在C语言中,函数是程序的基本模块,它们可以被独立编译并相互调用,使得代码组织更加清晰,便于重用和维护。本章主要介绍了函数的各个方面,包括概述、定义、返回值、调用、变量作用域和存储类别。 首先,函数大致...

    第6章 函数和递归(C++版) 第一节 函数

    ### 第6章 函数和递归(C++版) 第一节 函数 #### 知识点概述 在《第6章 函数和递归(C++版) 第一节 函数》这一章节中,主要介绍了C++编程语言中的函数概念及其使用方法。函数是一种重要的编程结构,可以帮助程序员更...

    C语言程序设计第六章函数.ppt

    C语言程序设计第六章函数 C语言程序设计第六章函数是C语言程序设计中的一部分,主要讲解了函数的概念、特点、分类和使用方式。 函数是一段程序,它完成特定的任务,使用它时可用简单的方法为其提供必要的数据,...

    优选c语言第六章函数PPT文档.ppt

    第六章主要探讨了函数的概念、定义、调用以及返回值,还涉及到了递推算法和递归的思想,以及函数参数的传递方式。 首先,函数是C语言中可重用的代码块,它执行特定任务并可能返回一个值。函数定义包括函数类型、...

    第3章 函数

    【第3章 函数】 在C++编程语言中,函数是一种组织代码的机制,它封装了一段可重复使用的代码块,执行特定的任务。函数能够提高代码的可读性,降低复杂性,使得程序设计更加模块化。本章将深入探讨C++中的函数,包括...

    Python基础入门教程 由浅入深讲解清晰 第5章 函数的设计和使用 (共49页).ppt

    【Python基础入门教程】深入解析第五章:函数的设计与使用 在Python编程中,函数是组织良好、可重用的代码块,它们允许我们将复杂的任务分解为一系列更小、更易于管理的部分。本章主要围绕函数的设计和使用展开,...

    c语言\第8章 函数.ppt

    在C语言中,函数是代码组织的基本单位,用于执行特定任务。第8章主要讨论了以下几个关键知识点: 1. **函数的定义与调用**:函数定义包括指定返回类型、函数名以及参数列表。例如,`int add(int a, int b) { return...

    第7章-用函数实现模块化程序设计.pptx

    ### 第7章-用函数实现模块化程序设计 #### 概述 本章节主要介绍了如何在C语言中利用函数来实现程序的模块化设计。模块化编程是一种将复杂程序分解成多个可管理的小块(模块)的技术,这些小块通常以函数的形式存在...

    第5章 函数和代码复用.pdf

    ### 第5章 函数和代码复用 #### 知识点概述 本章节主要围绕着函数的概念、定义、使用以及代码复用的方式展开讨论。针对Delphi环境下的Python语言程序设计,深入剖析了如何利用函数实现更高效、灵活的编程实践。 #...

    C语言课件(谭浩强):第六章 函数.ppt

    在C语言中,函数是实现模块化程序设计的关键要素,这一概念在第六章"函数"中得到深入探讨。模块化程序设计的基本思想是将大型的程序拆分成若干个小型、独立且具有单一功能的模块,这有助于降低程序的复杂性,提高...

    第6章 函数.pptx

    在Python编程语言中,函数是实现特定功能的代码块,它们可以帮助我们组织代码,提高代码的可读性和重用性。本章将深入探讨函数的使用,包括函数的定义、参数、返回值以及变量的作用域。 6.1 函数的定义 在Python中...

    第7章\_函数032.ppt

    本章主要讲解了C语言中函数的概念、结构以及使用方法。 1. **函数的概述** - 大型程序通常由多个模块组成,每个模块执行特定任务。 - 高级语言如C使用子程序(函数)来实现模块化。C程序由一个主函数(main函数)...

    第7章 函数1

    在JavaScript编程语言中,函数是极其重要的组成部分,它们允许我们将代码组织成可重用的模块。本章主要探讨了三个关键知识点:函数声明、return返回值以及arguments对象。 首先,函数声明是创建新函数的过程。在...

    C++Primer第五版 第6章 函数(练习解答)

    C++ Primer第五版第六章深入探讨了函数的各个方面,包括定义、调用、参数传递、返回值以及函数模板等核心概念。本章节的练习解答旨在帮助读者巩固这些知识,并通过实践提升对C++函数的理解。 1. **函数定义与声明**...

    重构_改善既有代码的设计

    第6章 重新组织函数  6.1 ExtractMethod(提炼函数)110  6.2 InlineMethod(内联函数)117  6.3 InlineTemp(内联临时变量)119  6.4 ReplaceTempwithQuery(以查询取代临时变量)120  6.5 ...

    Python语言程序设计教程 北理工Python课程第6章-函数与递归-2-函数的调用和返回值 共19页.pdf

    在第六章“函数与递归”中,我们重点讨论了函数的调用和返回值。 函数调用是程序执行过程中调用已定义函数的过程。调用函数时,会经历四个步骤:首先,调用程序在调用函数的位置暂停执行;接着,函数的形参接收实参...

    重构:改善既有代码的设计(中文版).

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    重构:改善既有代码的设计(中文高清版)

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    Python语言程序设计教程 北理工Python课程第6章-函数与递归-3-改变参数值的函数 共16页.pdf

    在第6章“函数与递归”中,我们深入探讨了如何使用函数,特别是那些能够改变参数值的函数。 首先,我们要明白在Python中函数是如何通过参数与调用程序传递信息的。在示例中,我们有一个`addInterest()`函数,它的...

Global site tag (gtag.js) - Google Analytics