首页 > 代码库 > 大话重构连载11:小步快跑是这样玩的

大话重构连载11:小步快跑是这样玩的

说了那么多。相信你对小步快跑的概念有了一个初步的印象,但理解还不是非常深。让我们来看一看一个实际工作中的样例,来亲身感受一下什么是大布局,什么是大设计。什么是小设计。

还是回到前面那个HelloWorld的样例,起初的需求总是简单而清晰的。

当用户登录一个站点时,站点往往须要给用户打一个招呼:“hi, XXX! ”。同一时候,假设此时是上午则显示“Good morning! ”,假设是下午则显示“Good afternoon! ”,除此显示“Good night! ”。

对于这样一个需求我们在一个HelloWorld类中写了十来行代码:

/**
 * The Refactoring‘s hello-world program
 * @author fangang
 */
public class HelloWorld {
	/**
	 * Say hello to everyone
	 * @param now
	 * @param user
	 * @return the words what to say
	 */
	public String sayHello(Date now, String user){
		//Get current hour of day
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(now);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		
		//Get the right words to say hello
		String words = null;
		if(hour>=6 && hour<12){
			words = "Good morning!";
		}else if(hour>=12 && hour<19){
			words = "Good afternoon!";
		}else{
			words = "Good night!";
		}
		words = "Hi, "+user+". "+words;
		return words;
	}
}


假设需求没有变更,一切都是美好的。

但事情总是这样,当软件第一次提交,变更就開始了。系统总是不能直接获得username称,而是先获得他的userId,然后通过userId从数据库中获得username。后面的问候可能须要更加精细,如中午问候“Good noon! ”、傍晚问候“Good evening! ”、午夜问候“Good midnight! ”。除此之外,用户希望在一些特殊的节日,如新年问候“Happy new year! ”、情人节问候“Happy valentine’s day! ”、三八妇女节问候“Happywomen’s day! ”。等等。除了已经列出的节日,他们还希望暂时加入一些特殊的日子,因此问候语须要形成一个库,并支持动态加入。不仅如此,这个问候库应当支持多语言,如选择英语则显示“Good morning! ”,而选择中文则显示“上午好!”……总之。各种不同的需求被源源不断地被用户提出来。因此我们的设计师開始头脑发热、充血、開始思维混乱。是的。假设你期望你自己能一步到位搞定全部这些需求。你必定会感到千头万绪、顾此失彼,进而做出错误的设计。但假设你学会了“小步快跑”的开发模式。一切就变得没有那么复杂了。

首先,我们观察原程序。发现它包括三个相对独立的功能代码段。因此我们採用重构中的“抽取方法”,将它们分别抽取到三个函数getHour(), getFirstGreeting(), getSecondGreeting()中,并让原函数对其引用:

 

/**
 * The Refactoring‘s hello-world program
 * @author fangang
 */
public class HelloWorld {
	/**
	 * Say hello to everyone
	 * @param now
	 * @param user
	 * @return the words what to say
	 */
	public String sayHello(Date now, String user){
		int hour = getHour(now);
		return getFirstGreeting(user)+getSecondGreeting(hour);
	}
	
	/**
	 * Get current hour of day.
	 * @param now
	 * @return current hour of day
	 */
	private int getHour(Date now){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(now);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}
	
	/**
	 * Get the first greeting.
	 * @param user
	 * @return the first greeting
	 */
	private String getFirstGreeting(String user){
		return "Hi, "+user+". ";
	}
	
	/**
	 * Get the second greeting.
	 * @param hour
	 * @return the second greeting
	 */
	private String getSecondGreeting(int hour){
		if(hour>=6 && hour<12){
			return "Good morning!";
		}else if(hour>=12 && hour<19){
			return "Good afternoon!";
		}else{
			return "Good night!";
		}
	}
}

这次重构尽管使程序结构发生了较大变化,但当中真正运行的代码却没有变化,还是那些代码。随后。我们核对需求发现,用户需求分成了两个不同的分支:对用户问候语的变更,和关于时间的问候语变更。为此,我们再次对HelloWorld的程序进行了分裂,运用重构中的“抽取类”,将对用户问候的程序分裂到GreetingToUser类中,将关于时间的问候程序分裂到GreetingAboutTime类中:

 

/**
 * The Refactoring‘s hello-world program
 * @author fangang
 */
public class HelloWorld {
	/**
	 * Say hello to everyone
	 * @param now
	 * @param user
	 * @return the words what to say
	 */
	public String sayHello(Date now, String user){
		GreetingToUser greetingToUser = new GreetingToUser(user);
		GreetingAboutTime greetingAboutTime = new GreetingAboutTime(now);
		return greetingToUser.getGreeting() + greetingAboutTime.getGreeting();
	}
}

/**
 * The greeting to user
 * @author fangang
 */
public class GreetingToUser {
	private String user;
	/**
	 * The constructor with user
	 * @param user
	 */
	public GreetingToUser(String user){
		this.user = user;
	}
	/**
	 * @return greeting to user
	 */
	public String getGreeting(){
		return "Hi, "+user+". ";
	}
}

/**
 * The greeting about time.
 * @author fangang
 */
public class GreetingAboutTime {
	private Date date;
	public GreetingAboutTime(Date date){
		this.date = date;
	}
	/**
	 * @param date
	 * @return the hour of day
	 */
	private int getHour(Date date){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}
	/**
	 * @return the greeting about time
	 */
	public String getGreeting(){
		int hour = getHour(date);
		if(hour>=6 && hour<12){
			return "Good morning!";
		}else if(hour>=12 && hour<19){
			return "Good afternoon!";
		}else{
			return "Good night!";
		}
	}
}

系统重构到这一步。我们来看看用户关于时间问候语部分的变更需求:问候须要更加精细,如中午问候“Good noon! ”、傍晚问候“Good evening! ”、午夜问候“Good midnight! ”。除此之外。用户希望在一些特殊的节日。如新年问候“Happy new year! ”、情人节问候“Happy valentine’s day! ”、三八妇女节问候“Happywomen’s day! ”,等等。此时我们发现。我们对时间问候语的变更不再须要改动HelloWorld或其他什么类,而是只专注于改动GreetingAboutTime就能够了,这就是因重构带来的改善。

同一时候。我们发现,过去仅仅需getHour()就足够,而如今却须要getMonth()与getDay()。随着程序复杂度的提升,我们适时进行了一次重构,将与时间相关的程序抽取到一个新类DateUtil中。就能够顺利地改写原有的时间问候语程序:

 

/**
 * The utility of time
 * @author fangang
 */
public class DateUtil {
	private Calendar calendar;
	/**
	 * @param date
	 */
	public DateUtil(Date date){
		calendar = Calendar.getInstance();
		calendar.setTime(date);
	}
	/**
	 * @return the hour of day
	 */
	public int getHour(){
		return calendar.get(Calendar.HOUR_OF_DAY);
	}
	/**
	 * @return the month of date
	 */
	public int getMonth(){
		return calendar.get(Calendar.MONTH)+1;
	}
	/**
	 * @return the day of month
	 */
	public int getDay(){
		return calendar.get(Calendar.DAY_OF_MONTH);
	}
}

/**
 * The greeting about time.
 * @author fangang
 */
public class GreetingAboutTime {
	private Date date;
	public GreetingAboutTime(Date date){
		this.date = date;
	}
	/**
	 * @return the greeting about time
	 */
	public String getGreeting(){
		DateUtil dateUtil = new DateUtil(date);
		int month = dateUtil.getMonth();
		int day = dateUtil.getDay();
		int hour = dateUtil.getHour();
		
		if(month==1 && day==1) return "Happy new year! ";
		if(month==1 && day==14) return "Happy valentine‘s day! ";
		if(month==3 && day==8) return "Happy women‘s day! ";
		if(month==5 && day==1) return "Happy Labor day! ";
		......
		
		if(hour>=6 && hour<12) return "Good morning!";
		if(hour==12) return "Good noon! ";
		if(hour>=12 && hour<19) return "Good afternoon! ";
		if(hour>=19 && hour<22) return "Good evening! ";
		return "Good night! ";
	}
}

最后,我们建立user表存放用户信息,创建UserDao接口及事实上现类。为GreetingToUser提供用户信息訪问的服务。我们用greetingRule表存放各种问候语,创建GreetingRuleDao接口及事实上现类,为GreetingAboutTime提供一个可扩展的、支持多语言的问候语库(如图3.1所看到的)。

全部这一切都是在现有基础上。通过小步快跑的方式一步一步演变的。

 技术分享

图3.1 HelloWorld的设计图

 

小步快跑是一种逐步进化式的程序优化过程,它是重构思想的重要核心。后面我们还会用很多其它实际工作中的演示样例,让你真实体会到小步快跑的开发过程。

大话重构连载首页:http://blog.csdn.net/mooodo/article/details/32083021

特别说明:希望网友们在转载本文时。应当注明作者或出处。以示对作者的尊重。谢谢!

大话重构连载11:小步快跑是这样玩的