类层次优于标签类
類層次優于標簽類
??有時候,可能會遇到帶有兩種甚至更多風格的實例代碼的類,并包含表示實例風格的標簽(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();}} }??這種標簽類有著許多的缺點。他們之中充斥著樣板代碼,包括枚舉聲明、標簽域以及條件語句。由于多個實現亂七八糟的擠在了單個類中,破壞了可讀性。內存的占用也增加了,因為實例承擔著屬于其他風格的不相干域。一句話,標簽類過于冗長、容易出錯,并且效率低下。
??幸運的是,面向對象語言例如Java,都提供了其他更好的方法來定義能表示多種風格對象的單個數據類型:子類型化。標簽類正是類層次的一種簡單的仿效。
??為了將標簽類轉變成類層次,首先要為標簽類中的每個方法都定義一個包含抽象方法的抽象類,這個方法的行為都依賴于標簽值。在Figure類中,只有一個這樣的方法:area。這個抽象類是類層次的根(root)。如果還有其他方法不依賴域標簽值,就把這樣的方法放在這個類中。
??接下來,為每種原始標簽類都定義根類的具體類。在前面的例子中,這樣的類型有兩個:圓形(circle)和矩形(rectangle)。在每個子類中都包含特定于該類型的數據域。在示例中,radius是特定于圓形,length和width是特定于矩形的。同時在每個子類中還包括針對于根類中的每個抽象方法的相應實現。
// 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);} }??這個類層次糾正了前面提到的標簽類的所有缺點。這段帶啊簡單且清楚,沒有包含在原來版本中所見到的所有樣板代碼。每個類型的實現都是自己的類,這些類都沒有受到不相關域的拖累。所有的域都是final的。編譯器確保每個類的構造方法都初始化它的數據域,對于根類中聲明的抽象方法,都確保有個實現。這樣就杜絕了由于遺漏switch case而導致的運行時失敗的可能。
??類層次的另一個好處在于,他們可以用來反映類之間本質上的層次關系,有助于增強靈活性,并進行更好的編譯時類型檢查。假設上述例子中的標簽類也允許表達正方形。類層次可以反映正方形是一種特殊的矩形這一事實(假設兩者都是不可變的):
class Square extends Rectangle{Square(double side){super(side,side);} }??注意,上述層次中的域是被直接訪問的,而不是通過訪問方法。這是為了簡潔起見才這樣做的,如果層次結構是公有的,則不允許這樣做。
??簡而言之,標簽類很少有適用的時候。當你想要編寫一個包含顯示標簽域的類時,應該考慮一下,這個標簽是否可以被取消,這個類是否可以用類層次來代替。當你遇到一個包含標簽的現有類時,就要考慮將它重構到一個層次結構中去。
轉載于:https://www.cnblogs.com/mr-cc/p/5798365.html
總結
- 上一篇: 【对比分析六】JavaScript中GE
- 下一篇: |Vijos|树状数组|P1512 Su