`
381895649
  • 浏览: 230336 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

java 代码重构-第一章(终于…我们来到继承(Inheritance))

    博客分类:
  • java
 
阅读更多

 

上一篇文章:java 代码重构-第一章(运用多态(Polymorphism)取代与价格相关的条件逻辑)

下一篇文章:java 代码重构-第一章(使用策略模式,把恶心的switch代码去掉...) 一

 

终于……我们来到继承(Inheritance)

我们有数种影片类型,它们以不同的方式回答相同的问题。这听起来很像subclasses 的工作。我们可以建立Movie 的三个subclasses ,每个都有自己的计费法(图1.14)。

这么一来我就可以运用多态(polymorphism)来取代switch 语句了。很遗憾的是这里有个小问题,不能这么干。一部影片可以在生命周期内修改自己的分类,一个对象却不能在生命周期内修改自己所属的class。不过还是有一个解决方法:State pattern(模式)[Gang of Four]。运用它之后,我们的classes 看起来像图1.15。

 

加入这一层间接性,我们就可以在Price 对象内进行subclassing 动作(译注:一如图1.15),于是便可在任何必要时刻修改价格。

 

如果你很熟悉Gang of Four 所列的各种模式(patterns),你可能会问:『这是一个State 还是一个Strategy?』答案取决于Price class 究竟代表计费方式(此时我喜欢把它叫做Pricer 或PricingStrategy),或是代表影片的某个状态(state,例如「Star Trek X 是一部新片」)。在这个阶段,对于模式(和其名称)的选择反映出你对结构的想法。此刻我把它视为影片的某种状态(state)。如果未来我觉得Strategy 能更好地说明我的意图,我会再重构它,修改名字,以形成Strategy 。

 

为了引入State 模式,我使用三个重构准则。首先运用Replace Type Code with State/Strategy,将「与型别相依的行为」(type code behavior )搬移至State 模式内。然后运用Move Method 将switch 语句移到Price class 里头。最后运用Replace Conditional with Polymorphism去掉switch 语句。

 

首先我要使用Replace Type Code with State/Strategy。第一步骤是针对「与 型别相依的行为」使用Self Encapsulate Field,确保任何时候都通过getting 和setting 两个函数来运用这些行为。由于多数代码来自其他classes,所以多数函数都己经使用getting 函数。但构造函数(constructor )仍然直接访问价格代号(译注:程序中的priceCode):

 

public Movie(String title, int priceCode) {
		this.title = title;
		this.priceCode = priceCode;
	}

 然后编译并测试,确保没有破坏任何东西。

 

输出结果:

 

Rental Record for oyhk 
	少林足球	6.0
	大话西游	1.5
Amount owed is 7.5
You earned 3 frequent renter points
------------------------------------------------
<H1>Rentals for <EM>oyhk</EM></ H1><P>
少林足球: 6.0<BR>
大话西游: 1.5<BR>
<P>You owe <EM>7.5</EM><P>
On this rental you earned <EM>3</EM> frequent renter points<P>

 证明重构没有错,结果跟上次的一样

 

下面是完整的代码:

Movie

 

package com.mkfree.refactoring.shap1;

/**
 * 电影类
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:55:14
 */
public class Movie {

	public static final int CHILDRENS = 2;
	public static final int REGULAR = 0;
	public static final int NEW_RELEASE = 1;

	public Movie(String title, int priceCode) {
		this.title = title;
		this.priceCode = priceCode;
	}

	private String title;
	private int priceCode;

	public String getTitle() {
		return title;
	}

	public int getPriceCode() {
		return priceCode;
	}

	/**
	 * 获取收费
	 * 
	 * @param daysRented
	 * @return
	 */
	double getCharge(int daysRented) {
		double result = 0;
		switch (getPriceCode()) {
		case Movie.REGULAR:
			result += 2;
			if (daysRented > 2)
				result += (daysRented - 2) * 1.5;
			break;
		case Movie.NEW_RELEASE:
			result += daysRented * 3;
			break;
		case Movie.CHILDRENS:
			result += 1.5;
			if (daysRented > 3)
				result += (daysRented - 3) * 1.5;
			break;
		}
		return result;

	}

	int getFrequentRenterPoints(int daysRented) {
		if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
			return 2;
		else
			return 1;
	}

}

 Rental

 

 

 

package com.mkfree.refactoring.shap1;

/**
 * 租凭
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:57:00
 */
public class Rental {

	private Movie movie;
	private int daysRented;

	public Rental(Movie movie, int daysRented) {
		this.movie = movie;
		this.daysRented = daysRented;
	}

	public Movie getMovie() {
		return movie;
	}

	public int getDaysRented() {
		return daysRented;
	}

	/**
	 * 把代码迁移到movie中
	 * 
	 * @return
	 */
	double getCharge() {
		return this.getMovie().getCharge(daysRented);
	}

	/**
	 * 获取经常的租赁
	 * 
	 * @return
	 */
	int getFrequentRenterPoints() {
		return this.getMovie().getFrequentRenterPoints(daysRented);
	}
}
 

 

Customer

 

package com.mkfree.refactoring.shap1;

import java.util.Enumeration;
import java.util.Vector;

/**
 * 顾客
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:59:03
 */
public class Customer {

	private String name;
	private Vectorrentals = new Vector<>();

	public Customer(String name) {
		this.name = name;
	}

	/**
	 * 添加
	 * 
	 * @param rental
	 */
	public void addRentals(Rental rental) {
		rentals.add(rental);
	}

	public String getName() {
		return name;
	}

	/**
	 * 通计清单
	 * 
	 * @return
	 */
	public String statement() {
		Enumerationenu_rentals = rentals.elements();
		String result = "Rental Record for " + this.getName() + " \n";
		while (enu_rentals.hasMoreElements()) {
			Rental each = enu_rentals.nextElement();
			result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(each.getCharge()) + "\n";
		}
		result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";
		result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points";
		return result;
	}

	// 此即所谓query method
	private double getTotalCharge() {
		double result = 0;
		Enumerationenu_rentals = rentals.elements();
		while (enu_rentals.hasMoreElements()) {
			Rental each = (Rental) enu_rentals.nextElement();
			result += each.getCharge();
		}
		return result;
	}

	// 此即所谓query method
	private int getTotalFrequentRenterPoints() {
		int result = 0;
		Enumerationenu_rentals = rentals.elements();
		while (enu_rentals.hasMoreElements()) {
			Rental each = (Rental) enu_rentals.nextElement();
			result += each.getFrequentRenterPoints();
		}
		return result;
	}

}

 

 Client

 

package com.mkfree.refactoring.shap1;

import org.junit.Test;

public class Client {

	@Test
	public void testStatement() {

		Movie movie1 = new Movie("少林足球", 1);
		Rental rental1 = new Rental(movie1, 2);

		Movie movie2 = new Movie("大话西游", 2);
		Rental rental2 = new Rental(movie2, 3);

		Customer customer = new Customer("oyhk");
		customer.addRentals(rental1);
		customer.addRentals(rental2);
		String statement = customer.statement();
		System.out.println(statement);
		System.out.println("------------------------------------------------");
		String htmlStatment = customer.htmlStatement();
		System.out.println(htmlStatment);
	}
}

 由于重构了Movie代码,对于Client当然也修改了一点点了...

 

本文章来自:http://blog.mkfree.com/posts/28

  • 大小: 24.4 KB
  • 大小: 24 KB
1
4
分享到:
评论

相关推荐

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

    第1章 重构,第一个案例 1 1.1 起点 1 1.2 重构的第一步 7 1.3 分解并重组statement() 8 1.4 运用多态取代与价格相关的条件逻辑 34 1.5 结语 52 第2章 重构原则 53 2.1 何谓重构 53 2.2 为何重构 ...

    重构_重构_改善既有代码_

    《重构:改善既有代码设计》是一本由Martin Fowler所著的经典IT著作,它详细阐述了在软件开发过程中如何通过重构来提升代码质量、可读性和维护性。重构是一种系统性的方法,旨在不改变软件外在行为的前提下,改进其...

    java程序设计-第5章-继承、多态、重载与接口

    Java只支持单继承,即一个子类只能有一个直接父类,但可以通过多重继承(接口)间接实现多继承的效果。所有类默认继承自`java.lang.Object`类。 2. **多态(Polymorphism)** 多态是面向对象的三大特性之一,指的...

    重构-改善既有代码的设计 中文版

    第1章 重构,第一个案例 1.1 起点 1.2 重构的第一步 1.3 分解并重组Statemen 1.4 运用多态取代与价格相关的条件逻辑 1.5 结语 第2章 重构原则 2.1 何谓重构 2.2 为何重构 2.3 何时重构 2.4 怎么对经理说 2.5 重构的...

    CC编程指南--第10章类的继承与组合.doc

    ### CC编程指南--第10章 类的继承与组合 #### 1. 继承 (Inheritance) 在面向对象编程中,“继承”是核心概念之一,它允许创建一个新类(派生类)来继承现有类(基类或父类)的属性和行为。这一特性不仅提高了代码...

    java---- 封装,接口,继承,覆盖,构造过程,多态,static、this、super、final用法

    通过以上对封装、继承、覆盖、构造过程、多态以及 `static`、`this`、`super` 和 `final` 关键字的详细介绍,我们可以更好地理解和运用Java的核心概念和技术点,从而编写出更加高效、灵活和易于维护的代码。

    java基础教程----精华版

    - **继承(Inheritance)**:一个类可以继承另一个类的特性,实现代码复用。 - **多态(Polymorphism)**:同一种行为可以有不同的表现形式,通过接口或抽象类实现。 3. **异常处理**: - Java使用try-catch-...

    重构-改善既有代码的设计+中文版

    Chapter 1:Refactoring,a First Example 重构,第一个例子   The Starting Point 起点   The First Step in Refactoring 重构第一步   Decomposing and Redistributing the Statement Method 分解并重组...

    JAVA知识整理-第一天.docx

    ### JAVA知识整理-第一天 #### 一、Java基础概念及特性 **1.1 Java语言特点** Java是一种广泛使用的高级编程语言,具有以下显著特点: - **可靠性**:Java通过严格的类型检查、自动垃圾回收机制等特性提高了代码...

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

    Chapter 1:Refactoring,a First Example 重构,第一个例子   The Starting Point 起点   The First Step in Refactoring 重构第一步   Decomposing and Redistributing the Statement Method 分解并重组...

    java程序代码-java开发学习之路

    本资源包"java程序代码-java开发学习之路"是为初学者精心准备的,旨在帮助初学者深入理解和实践Java开发技术。 首先,让我们从基础开始。Java的基础语法与C++相似,但更加简洁和安全。在Java中,一切皆为对象,这是...

    java oop总结-编程程序

    在 Java 面向对象(Object-Oriented Programming, OOP)编程中,我们主要关注以下几个核心概念:类(Class)、对象(Object)、封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)。这些概念构成了 ...

    inheritance---derived-class.rar_inheritance

    在C++编程语言中,继承(Inheritance)是面向对象编程的一个核心概念,它允许一个类(称为子类或派生类)从另一个类(称为基类或父类)继承特性。这种特性使得代码重用变得简单,同时也能实现多态性。"inheritance--...

    重构改善既有代码的设计(PDF)

    1. 代码坏味道的识别与处理:这是重构的第一步,需要识别代码中不健康的模式(即“坏味道”),如冗余代码、过长的方法、过大的类等。一旦识别出来,可以采用特定的重构手法来改善这些问题。 2. 提炼方法(Extract ...

    Java程序设计-源代码.rar

    4. **继承(Inheritance)**:Java支持单一继承,一个类可以继承另一个类的属性和方法,从而实现代码复用和多态性。 5. **接口(Interface)**:接口是完全抽象的类,只能包含常量和抽象方法。Java8引入了默认方法...

    Java语言程序设计_第4章_类的重用课件及源代码

    本节内容主要围绕“Java语言程序设计_第4章_类的重用”展开,通过“第4章 类的重用(熊).ppt”的课件和源代码,我们将深入探讨这个主题。 首先,类的重用主要体现在两个方面:继承(Inheritance)和接口...

    Java语言程序设计基础第十版第十一章课后复习题答案

    ### Java语言程序设计基础第十版第十一章课后复习题答案解析 #### 11.1 关于子类与父类的关系 - **题目**: 下面说法是真是假?一个子类是父类的子集。 - **答案**: 假,子类是父类的扩展,并不是子集。 - **解析**:...

    package-and-inheritance.zip_inheritance

    在Java编程语言中,封装、继承和多态是面向对象编程的三大核心概念,它们为构建复杂的软件系统提供了坚实的基础。下面将详细讲解这些概念及其重要性。 **封装**是面向对象编程的基本原则之一,它涉及到将数据和操作...

Global site tag (gtag.js) - Google Analytics