ivaneeo's blog

          自由的力量,自由的生活。

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks
          范例(Examples)
          本例從Change Unidirectional association to Bidirectional(197)留下的代碼開始進(jìn)行,其中CustomerOrder之間有雙向關(guān)聯(lián):
          class Order...
             Customer getCustomer() {
                return _customer;
             }
             void setCustomer(Custoemr arg) ...

                 if(_customer != null) _customer.friendOrders().remove(this);
                 _customer = arg;
                 if(_customer != null) _customer.friendOrders().add(this);
              }
             private Customer _customer;   //譯注:這是Order-to-Customer link也是本例的移除對象.

          class Customer ...
              void addOrder(Order arg) {
                 arg.setCustomer(this);
              }
             private Set _orders = new HashSet();
             //譯注:以上是Customer-to-Order link
             Set friendOrders() {
                 return _orders;
              }


          后來我發(fā)現(xiàn),除非先有Customer對象,否則不會(huì)存在Order對象.因此我想將[從Order到Customer的連接]移除掉.

          對于本項(xiàng)重構(gòu)來說,最困難的就是檢查可行性.如果我知道本項(xiàng)重構(gòu)是安全的,那么重構(gòu)手法自身十分簡單.問題在于是否有任何代碼倚賴_customer值域的存在.如果確實(shí)有,那么在刪除這個(gè)值域之后,我必須提供替代品.

          首先,我需要研究所有讀取這個(gè)值域的函數(shù),以及所有使用這些函數(shù)的函數(shù).我能找到另一條途徑來供應(yīng)Customer對象嗎----這通常意味將Customer對象作為引數(shù)(argument)傳遞給其用戶(某函數(shù)).下面是一個(gè)簡化例子:
          class Order...
             double getDiscountedPrice() {
                return getGrossPrice() * (1 - _customer.getDiscount());
             }

          改變?yōu)?
          class Order...
             double getDiscountedPrice(Customer customer) {
                return getGrossPrice() * (1 - customer.getDiscount());
             }

          如果待改函數(shù)是被Customer對象調(diào)用的,那么這樣的修改方案特別容易實(shí)施,因?yàn)镃ustomer對象將自己作為引數(shù)(argument)傳給函數(shù)很是容易.所以下列代碼:
          class Customer...
             double getPriceFor(Order order) {
                Assert.isTrue(_orders.contains(order));   //see
          Introduce Assertion(267)
                return order.getDiscountedPrice();

          變成了:
          class Customer...
             double getPriceFor(Order order) {
                Assert.isTrue(_orders.contains(order));
                return order.getDiscountedPrice(this);
          另一個(gè)作法就是修改取值函數(shù)(getter),使其在不使用_customer值域的前提下返回一個(gè)Customer對象.如果這行得通,我就可以使用Substitute Algorithm(139)修改Order.getCustomer()函數(shù)算法.我有可能這樣修改代碼:
          Customer getCustomer() {
             Iterator iter = Customer.getInstance().iterator();
             while(iter.hasNext()) {
                Customer each = (Customer)iter.next();
                if(each.containsOrder(this) return each;
             }
             return null;
          }

          這段代碼比較慢,不過確實(shí)可行.而且,在數(shù)據(jù)庫環(huán)境下,如果我需要使用數(shù)據(jù)庫查詢語句,這段代碼對系統(tǒng)性能的影響可能并不顯著.如果,Order class中有些函數(shù)使用_customer值域,我可以實(shí)施Self Encapsulate Field(171)令它們轉(zhuǎn)而改用上述的getCustomer()函數(shù).

          如果我要保留上述的取值函數(shù)(getter),那么OrderCustomer的關(guān)聯(lián)從接口上看雖然仍然是雙向,但實(shí)現(xiàn)上已經(jīng)是單向關(guān)系了.雖然我移除了反向指針,但兩個(gè)classes彼此之間的依存關(guān)系(inter-dependencies)仍然存在.

          如果我要替換取值函數(shù)(getter),那么我就專注地替換它,其他部分留待以后處理.我會(huì)逐一修改取值函數(shù)的調(diào)用者.讓它們通過其他來源取得Customer對象.每次修改后都編譯并測試.實(shí)際工作中這一過程往往相當(dāng)快.如果這個(gè)過程讓我覺得很棘手很復(fù)雜,我會(huì)放棄本項(xiàng)重構(gòu).

          一旦我消除了_customer值域的所有讀取點(diǎn),我就可以著手處理[對此值域進(jìn)行賦值動(dòng)作]的函數(shù)了.很簡單,只要把這些賦值動(dòng)作全部移除,再把值域一并刪除,就行了.由于已經(jīng)沒有任何代碼需要這個(gè)值域,所以刪掉它并不會(huì)帶來任何影響.
          posted on 2005-09-14 17:29 ivaneeo 閱讀(294) 評論(0)  編輯  收藏 所屬分類: refactoring-從地獄中重生
          主站蜘蛛池模板: 江油市| 旺苍县| 固镇县| 锡林郭勒盟| 海兴县| 普兰店市| 建德市| 青川县| 平遥县| 上蔡县| 鄂托克旗| 扶余县| 瑞安市| 铁力市| 兴城市| 方城县| 同仁县| 祁连县| 澎湖县| 红桥区| 八宿县| 那坡县| 京山县| 宽甸| 内黄县| 含山县| 湟源县| 溆浦县| 孟村| 鸡东县| 井研县| 怀仁县| 寻乌县| 武隆县| 遂昌县| 东兰县| 德保县| 雅安市| 昆明市| 秦皇岛市| 泸溪县|