程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> EffectiveJava——類層次優於標簽類,effectivejava優於

EffectiveJava——類層次優於標簽類,effectivejava優於

編輯:JAVA綜合教程

EffectiveJava——類層次優於標簽類,effectivejava優於


標簽類:

有時候,可能會遇到帶有兩種甚至更多鐘風格的類的實例的類,並包含表示實例風格的(tag)域。例如下面這個類,它能夠表示圓形或者矩形:

/**
 * 類層次優先與標簽類
 * @author weishiyao
 *
 */
// Tagged class - vastly inferior to a class hierarchy
public class Figure1{
	enum Shape {
		RECTANGLE,
		CIRCLE
	}
	
	// Tag field - the shape of this figure
	final Shape shape;
	
	// These field are use only if shape if RECTANGLE
	double length;
	double width;
	
	// This field is use only if shape is CIRCLE
	double radius;
	
	// Constructor for circle
	public Figure1(double radius) {
		shape = Shape.CIRCLE;
		this.radius = radius;
	}
	
	// Constructor for rectangle
	public Figure1(double length, double width) {
		shape = Shape.RECTANGLE;
		this.length = length;
		this.width = width;
	}
	
	double area() {
		switch (shape) {
		case RECTANGLE:
			return length * width;
		case CIRCLE:
			return Math.PI * (radius * radius);
		default:
			throw new AssertionError();
		}
	}
}

  這種標簽類有著許多缺點:

1.它們中充斥著樣板代碼,包括枚舉聲明,標簽域以及條件語句。由於許多個實現亂七八糟的擠在了單個類中,破壞了可讀性。

2.內存占用也增加了,因為實例承擔了屬於其他風格的不相關的域。

3.域也不能做成final類型的,除非構造器初始化了不相關的域,產生了更多的樣板代碼。構造器必須不借助編譯器,來設置標簽域,並且初始化正確的數據域;如果初始化了錯誤的域,程序就會在運行的時候出錯。

4.無法給標簽類添加風格,除非可以修改源文件,如果一定要添加風格,就必須給每個條件語句都添加一個條件,否則就會在運行的時候失敗。

5.最後,實例的數據類型沒有提供任何關於其風格的線索

總結:標簽類過於冗長、容易出錯,並且效率低下

  幸運的是,面向對象的語言java,提供了其他更好的方法來定義能表示多種風格對象的單個數據類型:子類型化。標簽類正是類層次的一種簡單效仿。

  為了將標簽類轉化成類層次,首先要為標簽類中的每一個方法都定義一個包含抽象方法的抽象類,這每個方法的行為都依賴於標簽值。在Figure類中,只有一個這樣的方法:area。這個抽象類是類層次的根。如果還有其他的方法行為不依賴於某個標簽的值,就把這樣的方法放到這個類中。同樣的,如果所有的方法都用到了某些數據域,就應該把他們放在這個類中。在Figure類中,不存在這種類型獨立的方法或者數據域。

/**
 * 類層次優於標簽類
 * @author weishiyao
 *
 */
// Class hierarchy replacement for a tagged class
abstract class Figure2 {
	abstract double area();
}

class Circle extends Figure2 {
	final double radius;
	
	Circle(double radius) {
		this.radius = radius;
	}
	
	double area() {
		return Math.PI * (radius * radius);
	}
}

class Rectangle extends Figure2 {
	final double length;
	final double width;
	
	Rectangle(double length, double width) {
		this.length = length;
		this.width = width;
	}
	double area() {
		return length * width;
	}
}

  這個類糾正了前面提到過的標簽類的所有缺點。這段代碼簡單且清楚,沒有包含在原來版本中所見到的所有樣板代碼。每個類型都有自己的類,這些類都沒有受到不相關的數據域的拖累。所有的域都是final的。編譯器確保每個類的構造器都初始化它的數據域,對於根類中聲明的每個抽象方法,都確保有一個實現。這樣就杜絕了由於遺漏switch case而導致運行失敗的可能性。多個程序員都可以獨立的擴展層次結構,並且不用訪問根類的資源代碼就能互相操作。每種類型都有一種相關的獨立的數據類型,允許程序員指明變量類型,限制變量,並將參數輸入到特殊的類型。

  類層次的另一個好處在於,它們可以用來反應類型之間本質上的層次關系,有助於增強靈活性,並更好的進行編譯時類型檢查。

  總而言之,標簽類很少有適用的時候。當你想要編寫一個包含顯示的標簽域的類時,應該考慮一下,這個標簽是否可以被取消,這個類是否可以用類層次來代替,當你遇到一個包含標簽域的現有類時,就要考慮將它重構到一個層次結構中去。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved