<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### Extract Subclass(提煉子類) class 中的某些特性(features)只被某些(而非全部)實體(instances)用到。 新建一個subclass ,將上面所說的那一部分特性移到subclass 中。 ![](https://box.kancloud.cn/2016-08-15_57b1b5e6dfdfe.gif) **動機(Motivation)** 使用Extract Subclass 的主要動機是:你發現class 中的某些行為只被一部分實體用到,其他實體不需要它們。有時候這種行為上的差異是通過type code 區分 的,此時你可以使用 Replace Type Code with Subclasses 或 Replace Type Code with State/Strategy。但是,并非一定要出現了type code 才表示需要考慮使用subclass 。 Extract Class 是Extract Subclass 之外的另一種選擇,兩者之間的抉擇其實就是委托(delegation)和繼承(inheritance)之間的抉擇。Extract Subclass 通常更容易進行,但它也有限制:一旦對象創建完成,你無法再改變「與型別相關的行為」(class-based behavior )。但如果使用Extract Class ,你只需插入另一個不同組件( plugging in different components)就可以改變對象的行為。此外,subclasses 只能用以表現一組變化(one set of variations)。如果你希望class 以數種不同的方式變化,就必須使用委托(delegation)。 **作法(Mechanics)** - 為source class 定義一個新的subclass 。 - 為這個新的subclass 提供構造函數。 - 簡單的作法是:讓subclass 構造函數接受與superclass 構造函數相同的參數,并通過super 調用superclass 構造函數。 - 如果你希望對用戶隱藏subclass 的存在,可使用Replace Constructor with Factory Method。 - 找出調用superclass 構造函數的所有地點。如果它們需要的是新建的subclass , 令它們改而調用新構造函數。 - 如果subclass 構造函數需要的參數和superclass 構造函數的參數不同,可以使用Rename Method 修改其參數列。如果subclass 構造函數不需要superclass 構造函數的某些參數,可以使用Rename Method 將它們去除。 - 如果不再需要直接實體化(具現化,instantiated)superclass ,就將它聲明為抽象類。 - 逐一使用Push Down Method 和 Push Down Field 將source class 的特性移到subclass 去。 - 和Extract Class 不同的是,先處理函數再處理數據,通常會簡單一些。 - 當一個public 函數被下移到subclass 后,你可能需要重新定義該函數的調用端的局部變量或參數型別,讓它們改調用subclass 中的新函數。如果忘記進行這一步驟,編譯器會提醒你。 - 找到所有這樣的值域:它們所傳達的信息如今可由繼承體系自身傳達(這一類值域通常是boolean 變量或type code )。以 Self Encapsulate Field 避免直接使用這些值域,然后將它們的取值函數(getter)替換為多態常量函數(polymorphic constant methods)。所有使用這些值域的地方都應該以Replace Conditional with Polymorphism 重構。 - 任何函數如果位于source class 之外,而又使用了上述值域的訪問函數(accessors),考慮以 Move Method 將它移到source class 中, 然后再使用Replace Conditional with Polymorphism。 - 每次下移之后,編譯并測試。 **范例:(Example)** 下面是JobItem class,用來決定當地修車廠的工作報價: ~~~ class JobItem ... public JobItem (int unitPrice, int quantity, boolean isLabor, Employee employee) { _unitPrice = unitPrice; _quantity = quantity; _isLabor = isLabor; _employee = employee; } public int getTotalPrice() { return getUnitPrice() * _quantity; } public int getUnitPrice(){ return (_isLabor) ? _employee.getRate(): _unitPrice; } public int getQuantity(){ return _quantity; } public Employee getEmployee() { return _employee; } private int _unitPrice; private int _quantity; private Employee _employee; private boolean _isLabor; class Employee... public Employee (int rate) { _rate = rate; } public int getRate() { return _rate; } private int _rate; ~~~ 我要提煉出一個LaborItem subclass,因為上述某些行為和數據只在labor (勞工) 情況下才需要。首先建立這樣一個class: ~~~ class LaborItem extends JobItem {} ~~~ 我需要為LaborItem 提供一個構造函數,因為JobItem 沒有「無引數構造函數」 ( no-arg constructor)。我把superclass 構造函數的參數列拷貝過來: ~~~ public LaborItem (int unitPrice, int quantity, boolean isLabor, Employee employee) { super (unitPrice, quantity, isLabor, employee); } ~~~ 這就足以讓新的subclass 通過編譯了。但是這個構造函數會造成混淆:某些參數是LaborItem 所需要的,另一些不是。稍后我再來解決這個問題。 下一步是要找出對JobItem 構造函數的調用,并從中找出「可替換為LaborItem 構造函數」者。因此,下列語句: ~~~ JobItem j1 = new JobItem (0, 5, true, kent); ~~~ 就被修改為: ~~~ JobItem j1 = new LaborItem (0, 5, true, kent); ~~~ 此時我尚未修改變量型別,只是修改了構造函數所屬的class 。之所以這樣做,是因為我希望只在必要地點才使用新型別。到目前為止,subclass 還沒有專屬接口,因 此我還不想宣布任何改變。 現在正是清理構造函數參數列的好時機。我將針對每個構造函數使用Rename Method。首先處理superclass 構造函數。我要新建一個構造函數,并把舊構造函數聲明為protected (不能直接聲明為private ,因為subclass 還需要它): ~~~ class JobItem... protected JobItem (int unitPrice, int quantity, boolean isLabor, Employee employee) { _unitPrice = unitPrice; _quantity = quantity; _isLabor = isLabor; _employee = employee; } public JobItem (int unitPrice, int quantity) { this (unitPrice, quantity, false, null) } ~~~ 現在,外部調用應該使用新構造函數: ~~~ JobItem j2 = new JobItem (10, 15); ~~~ 編譯、測試都通過后,我再使用 Rename Method 修改subclass 構造函數: ~~~ class LaborItem public LaborItem (int quantity, Employee employee) { super (0, quantity, true, employee); } ~~~ 此時的我仍然暫時使用protected superclass 構造函數。 現在,我可以將JobItem 的特性向下搬移。先從函數幵始,我先運用 Push Down Method 對付getEmployee() 函數: ~~~ class LaborItem... public Employee getEmployee() { return _employee; } class JobItem... protected Employee _employee; ~~~ 因為_employee 值域也將在稍后被下移到LaborItem ,所以我現在先將它聲明為protected。 將_employee 值域聲明protected 之后,我可以再次清理構造函數,讓_employee 只在「即將去達的subclass 中」被初始化: ~~~ class JobItem... protected JobItem (int unitPrice, int quantity, boolean isLabor) { _unitPrice = unitPrice; _quantity = quantity; _isLabor = isLabor; } class LaborItem ... public LaborItem (int quantity, Employee employee) { super (0, quantity, true); _employee = employee; } ~~~ _isLabor 值域所傳達的信息,現在已經成為繼承體系的內在信息,因此我可以移 除這個值域了。最好的方式是:先使用Self Encapsulate Field,然后再修改訪問函數(accessors),改用多態常量函數。所謂「多態常量函數」會在不同的subclass 實現版本中返回不同的固定值: ~~~ class JobItem... protected boolean isLabor() { return false; } class LaborItem... protected boolean isLabor() { return true; } ~~~ 然后,我就可以擺脫_isLabor 值域了。 現在,我可以觀察isLabor() 函數的用戶,并運用Replace Conditional with Polymorphism 重構它們。我找到了下列這樣的函數: ~~~ class JobItem... public int getUnitPrice(){ return (isLabor()) ? _employee.getRate(): _unitPrice; } ~~~ 將它重構為: ~~~ class JobItem... public int getUnitPrice(){ return _unitPrice; } class LaborItem... public int getUnitPrice(){ return _employee.getRate(); } ~~~ 當使用某項值域的函數全被下移至subclass 后,我就可以使用 Push Down Field 將值域也下移。如果尚還無法移動值域,那就表示,我需要對函數做更多處理,可能需要實施Push Down Method 或 Replace Conditional with Polymorphism。 由于_unitPrice 值域只被LaborItem 以外的對象(也就是parts job items)所用, 所以我可以再次運用Extract Subclass 對JobItem 提煉出一個subclass :PartsItem 。完成后,我可以將JobItem 聲明為抽象類。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看