类层次优于标签类
類層次優(yōu)于標(biāo)簽類
??有時(shí)候,可能會遇到帶有兩種甚至更多風(fēng)格的實(shí)例代碼的類,并包含表示實(shí)例風(fēng)格的標(biāo)簽(tag)域。例如,考慮下面這個類,它能夠表示圓形或者矩形:
// Tagged class - vastly inferior to a class hierarchy! class Figure{enum Shape{RECTANGLE,CIRCLE};//Tag field - the shape of this figurefinal Shape shape;//There field are used only if shape is RECTANGLEdouble length;double width;//This field is used only if shape is CIRCLEdouble radius;//Constructor for circleFigure(double radius){shape = Shape.CIRCLE;this.radius = radius;}//Constructor for rectangleFigure(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();}} }??這種標(biāo)簽類有著許多的缺點(diǎn)。他們之中充斥著樣板代碼,包括枚舉聲明、標(biāo)簽域以及條件語句。由于多個實(shí)現(xiàn)亂七八糟的擠在了單個類中,破壞了可讀性。內(nèi)存的占用也增加了,因?yàn)閷?shí)例承擔(dān)著屬于其他風(fēng)格的不相干域。一句話,標(biāo)簽類過于冗長、容易出錯,并且效率低下。
??幸運(yùn)的是,面向?qū)ο笳Z言例如Java,都提供了其他更好的方法來定義能表示多種風(fēng)格對象的單個數(shù)據(jù)類型:子類型化。標(biāo)簽類正是類層次的一種簡單的仿效。
??為了將標(biāo)簽類轉(zhuǎn)變成類層次,首先要為標(biāo)簽類中的每個方法都定義一個包含抽象方法的抽象類,這個方法的行為都依賴于標(biāo)簽值。在Figure類中,只有一個這樣的方法:area。這個抽象類是類層次的根(root)。如果還有其他方法不依賴域標(biāo)簽值,就把這樣的方法放在這個類中。
??接下來,為每種原始標(biāo)簽類都定義根類的具體類。在前面的例子中,這樣的類型有兩個:圓形(circle)和矩形(rectangle)。在每個子類中都包含特定于該類型的數(shù)據(jù)域。在示例中,radius是特定于圓形,length和width是特定于矩形的。同時(shí)在每個子類中還包括針對于根類中的每個抽象方法的相應(yīng)實(shí)現(xiàn)。
// Class hierarchy repalcement for a tagged class abstract class Figure{abstract double area(); } class Circle extends Figure{final double radius;Circle(double radius){this.radius = radius}double area(){return Math.PI * (radius * radius);} } class Rectangle extends Figure{final double length;final double width;Rectangle(double length,double width){this.length = length;this.width = width;}double area(){return (length * width);} }??這個類層次糾正了前面提到的標(biāo)簽類的所有缺點(diǎn)。這段帶啊簡單且清楚,沒有包含在原來版本中所見到的所有樣板代碼。每個類型的實(shí)現(xiàn)都是自己的類,這些類都沒有受到不相關(guān)域的拖累。所有的域都是final的。編譯器確保每個類的構(gòu)造方法都初始化它的數(shù)據(jù)域,對于根類中聲明的抽象方法,都確保有個實(shí)現(xiàn)。這樣就杜絕了由于遺漏switch case而導(dǎo)致的運(yùn)行時(shí)失敗的可能。
??類層次的另一個好處在于,他們可以用來反映類之間本質(zhì)上的層次關(guān)系,有助于增強(qiáng)靈活性,并進(jìn)行更好的編譯時(shí)類型檢查。假設(shè)上述例子中的標(biāo)簽類也允許表達(dá)正方形。類層次可以反映正方形是一種特殊的矩形這一事實(shí)(假設(shè)兩者都是不可變的):
class Square extends Rectangle{Square(double side){super(side,side);} }??注意,上述層次中的域是被直接訪問的,而不是通過訪問方法。這是為了簡潔起見才這樣做的,如果層次結(jié)構(gòu)是公有的,則不允許這樣做。
??簡而言之,標(biāo)簽類很少有適用的時(shí)候。當(dāng)你想要編寫一個包含顯示標(biāo)簽域的類時(shí),應(yīng)該考慮一下,這個標(biāo)簽是否可以被取消,這個類是否可以用類層次來代替。當(dāng)你遇到一個包含標(biāo)簽的現(xiàn)有類時(shí),就要考慮將它重構(gòu)到一個層次結(jié)構(gòu)中去。
轉(zhuǎn)載于:https://www.cnblogs.com/mr-cc/p/5798365.html
總結(jié)
- 上一篇: 【对比分析六】JavaScript中GE
- 下一篇: |Vijos|树状数组|P1512 Su