<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      對象命名為何需要避免'-er'和'-or'后綴

      之前寫過兩篇關(guān)于軟件工程中對象命名的文章:開發(fā)中對象命名的一點思考對象命名怎么上手?從現(xiàn)實世界,但感覺還是沒有說透,

      在軟件工程中,如果問我什么最重要,我的答案是對象命名。良好的命名能夠反映系統(tǒng)的本質(zhì),使代碼更具可讀性和可維護性。本文通過具體例子,探討為何應(yīng)該以對象本質(zhì)而非功能來命名,以及不當(dāng)命名可能帶來的長期問題。

      一個例子

      這個例子是我最近看到的一段代碼,用于解釋SOLID中的依賴倒置原則的好處用來隔離變化,代碼如下:

      public interface IPaymentProcessor
      {
          void ProcessPayment(decimal amount);
      }
      
      public class CreditCardPaymentProcessor : IPaymentProcessor
      {
          public void ProcessPayment(decimal amount)
          {
              // 信用卡支付的具體實現(xiàn)
          }
      }
      
      public class PayPalPaymentProcessor : IPaymentProcessor
      {
          public void ProcessPayment(decimal amount)
          {
              // PayPal支付的具體實現(xiàn)
          }
      }

       

      如之前文章提到,er或or結(jié)尾的命名,本質(zhì)上是動詞+施動者后綴組成的,本質(zhì)是詞匯匱乏的表現(xiàn),這種其實可以有很多,比如:

      • Executor(執(zhí)行者)
      • Handler(處理者)
      • Provider(提供者)
      • Builder(構(gòu)建者)
      • Dispatcher(調(diào)度者)
      • Processor(處理器)
      • Checker(檢查者)
      • Manager(管理者)
      • Converter(轉(zhuǎn)換者)
      • Watcher(觀察者)
      • Runner(運行者)
      • Fetcher(獲取者)
      • Adapter(適配者)
      • Keeper(保持者)
      • Coordinator(協(xié)調(diào)者)

       

      這些命名在現(xiàn)代軟件工程中非常常見,但并不代表正確,本質(zhì)是面向過程的命令式編程,而不是面向?qū)ο蟾F(xiàn)代的聲明式編程,會潛移默化影響我們的思維方式。

       

      問題在哪

      這種命名方式更多強調(diào)對象的更能,而非本質(zhì),命名應(yīng)該遵循以事物本質(zhì)命名,而不是事物做什么(what the object is, not what it does)。

      下面我們以另一個案例來看,例如,我希望設(shè)計一個對象,該對象用于滿足人類坐下時的支撐需求,那么應(yīng)該叫什么?如果按照IPaymentProcessor例子中提到的同樣命名規(guī)則,則應(yīng)該使用“人體支撐器”,而不是椅子。

       

      下面是代碼示例:

      class HumanSupporter {
        supportHuman() { /* ... */ }
      }

       

      缺乏時間韌性

      這種命名,可能是由于在當(dāng)前上下文中,我們僅考慮椅子用于坐的功能這一點,并沒有考慮未來的需求,后續(xù),例如我們希望在椅子下面儲存一些東西,該怎么做?

      第一種選項是修改對象名稱,以滿足新的需求:

      // 選項1:改名(同時修改所有引用...)
      class HumanSupporterAndItemStorer { 
        supportHuman() { /* ... */ }
        storeItems() { /* ... */ }
      }

       

      第二種選項,也是我們實際上使用最多的辦法,無視類名稱,直接硬加一個方法,反正過幾個月這個東西不一定是誰負責(zé)了-.-

      // 選項2:保留不準確的名稱(誤導(dǎo)接盤俠)
      class HumanSupporter {
        supportHuman() { /* ... */ }
        storeItems() { /* ... */ } // 名稱與功能不符
      }

       

      第三種選項,將功能隔離到一個單獨類中,但隨著這類需求的增多,很多分散的類之間會存在復(fù)雜的調(diào)用關(guān)系,同時新增類由于是臨時起意設(shè)計出來,很難在后續(xù)的功能中復(fù)用:

      // 選項3:創(chuàng)建新類(功能分散,關(guān)系復(fù)雜)
      class ItemStorer {
        storeItems() { /* ... */ }
      }

       

      而當(dāng)我們使用更符合本質(zhì)的命名時,代碼演進的節(jié)奏如下:

      // 初始版本
      class Chair {
        sitOn() { /* ... */ }
      }
      
      // 第二版本 - 增加存儲功能
      class Chair {
        sitOn() { /* ... */ }
        storeItemsUnderneath() { /* ... */ } // 自然擴展,符合椅子的本質(zhì)
      }
      
      // 需要更專業(yè)化時,創(chuàng)建子類
      class StorageChair extends Chair {
        // 擴展而非替代,保持概念一致性
      }

       

      基于對象本質(zhì)的命名可以看出擁有足夠的時間韌性。

       

      命名過于抽象或泛化可能導(dǎo)致膨脹

      “人體支撐器”這種命名很容易讓類的膨脹顯得合情合理,首先從語義上來看,"-er"/"-or"結(jié)尾的詞在語法上創(chuàng)造了一個施動者(agent),但語義邊界不清。"人體支撐器"到底支撐什么?支撐到什么程度?

      同時強調(diào)行為,而淡化對象的本質(zhì)。

      同時"支撐器"從語義學(xué)角度存在雙重問題:

      上位詞過寬:支撐器是椅子、凳子、桌子、沙發(fā)等眾多物品的上位詞,失去了分類的精確性。語言學(xué)中,這種上位詞(hypernym)過于寬泛時,語義信息密度大幅降低。同時引起抽象維度的混亂,可能導(dǎo)致很多不相干的內(nèi)容全部塞進類中。

      下位詞過窄:將椅子定義為"支撐器"忽略了其他屬性——舒適性、美學(xué)價值、文化符號意義。這是語義要素(semantic features)的不當(dāng)減少。

       

      隨著演進,我們可能看到這樣一個類的膨脹方式:

      class HumanSupporter {
          public void supportHuman() {
              // 原始功能
          }
          
          public void maintainPosture() {
              // 第二版添加的功能
          }
          
          // 存儲物品也可以解釋為"支持人類活動"的一部分
          public void storeItems() {
              // 存儲物品的實現(xiàn)
          }
          
          // 在模糊的功能定義下,越來越多不相關(guān)的功能被添加進來
          public void provideWarmth() {
              // 提供溫暖的實現(xiàn)
          }
          
          public void massageUser() {
              // 按摩功能實現(xiàn)
          }
          
          // 完全不相關(guān)的功能也可以通過寬泛解釋而加入
          public void playMusic() {
              // "這也是支撐人類放松,對吧?"
          }
          
          public void chargeMobileDevices() {
              // "現(xiàn)代人需要充電,這也是支持現(xiàn)代人類的需求!"
          }
          
          // 隨著時間推移,類可能繼續(xù)膨脹...
          public void provideSnacks() {
              // "提供零食也是支撐人體的一種方式!"
          }
          
          public void controlRoomLighting() {
              // "控制燈光也是為了支持人類工作環(huán)境!"
          }
          
          // 很多功能都可以塞進這種不當(dāng)?shù)某橄笾?..
      }

       

      從例子中看貌似有點夸張,但只要Codebase生命周期足夠久,就能看到許多瘋狂膨脹的類,如果沒有監(jiān)督或嚴格的Code Review,人們會傾向于短平快的實現(xiàn)手段,我見過很多后綴為Handler、base、manager的類膨脹到上萬行,被上百處引用。

      而使用符合本質(zhì)的命名時,新增功能如下:

      * Chair - 椅子
       * 初始設(shè)計:簡單的椅子類
       */
      class Chair {
          // 核心功能明確定義了椅子的基本用途
          public void sitOn() {
          }
      }
      
      /**
       * Chair - 第二版
       * 增加了新功能,但都嚴格符合"椅子"的本質(zhì)特性
       */
      class Chair {
          public void sitOn() {
              // 坐的實現(xiàn)
          }
          
          // 存儲物品在椅子下方是椅子的自然擴展,符合我們對椅子的理解
          public void storeItemsUnderneath() {
              // 存儲功能實現(xiàn)
          }
          
          // 調(diào)整高度也是椅子可能具有的功能
          public void adjustHeight() {
              // 高度調(diào)整實現(xiàn)
          }
          
          // 注意:我們不會想到給椅子添加"播放音樂"的功能
          // 因為這明顯不符合我們對"椅子"這個概念的理解
      }
      
      /**
       * 當(dāng)需要更多功能時,我們創(chuàng)建專門的子類
       * 而不是向基類添加不相關(guān)的功能
       */
      class StorageChair extends Chair {
          // 擴展存儲功能,而不是改變椅子的基本概念
          @Override
          public void storeItemsUnderneath() {
              // 增強的存儲功能實現(xiàn)
          }
          
          // 添加符合"儲物椅"概念的特殊功能
          public void openStorage() {
              // 打開儲物區(qū)實現(xiàn)
          }
      }
      
      class Massager {
          // 單一職責(zé):專注于按摩功能
          public void massageUser() {
          }
      }
      
      // 使用組合將按摩功能添加到椅子中,直接定義,或通過構(gòu)造函數(shù)注入或DI
      class MassageChair extends Chair {
          private Massager massager;
          
          // 通過組合添加按摩功能,而不是直接在Chair類中添加
          public void activateMassage() {
          }
      }

       

      類圖如下:

       

      我們可以看到,HumanSupporter (功能性命名) 隨著需求增加容易變得臃腫,因為幾乎任何功能都可以歸為"支持人類",Chair (實體命名) 自然限制了類的職責(zé)范圍,不相關(guān)功能明顯感覺格格不入,當(dāng)需要添加新功能時,具體命名引導(dǎo)我們創(chuàng)建專門的子類或使用組合,而不是膨脹基類。

       

      命名增加認知負載

      HumanSupporter這種不符合我們?nèi)粘=涣髦械牧?xí)慣,屬于開發(fā)人員在開發(fā)過程中的臨場發(fā)揮,現(xiàn)實世界中并沒有“人體支撐器”這種抽象的概念。而椅子(Chair)的概念在現(xiàn)實生活中非常容易理解,其職責(zé)和邊界在現(xiàn)實世界這么多年的演化中基本穩(wěn)定,那么在短暫的軟件生命周期中也應(yīng)該是穩(wěn)定的。

      同時在代碼抽象角度,現(xiàn)實生活中的概念更容易進行抽象,同時抽象維度也會比較合理,例如:

      HumanSupporter可能繼承自Supporter,但這個繼承層次是否有意義?這種功能性抽象通常是臨時起意,并不健壯,而Chair、Table可以更自然的抽象成Furniture,這反映了真實世界的抽象規(guī)則。

      同時在和其他開發(fā)人員或業(yè)務(wù)人員溝通時,請把“請把人體支撐器搬過來”,這種溝通會不會讓人抓狂?

      那么開頭例子該如何重構(gòu)?

      通過易于理解的椅子代碼示例,理解對象命名的重要性,那么對于開頭的例子IPaymentProcessor接口,直接重構(gòu)為更符合本質(zhì)的IPayment即可,有什么好處?

       

      功能擴展對比

      IPaymentProcessor:添加功能需修改接口

      // 原始接口
      public interface IPaymentProcessor {
          void ProcessPayment(decimal amount);
      }
      
      // 需要添加退款功能 - 所有實現(xiàn)類都必須修改
      public interface IPaymentProcessor {
          void ProcessPayment(decimal amount);
          void ProcessRefund(string transactionId, decimal amount); // 新增方法
      }
      
      // 所有實現(xiàn)類都被迫實現(xiàn)新方法
      public class PayPalPaymentProcessor : IPaymentProcessor {
          public void ProcessPayment(decimal amount) { /* 原有代碼 */ }
          
          // 即使此支付方式不支持退款,也必須實現(xiàn)
          public void ProcessRefund(string transactionId, decimal amount) {
              throw new NotSupportedException("PayPal不支持退款");
          }
      }

      IPayment:添加功能通過擴展接口

      // 原始接口保持不變
      public interface IPayment {
          PaymentResult Execute(decimal amount);
      }
      
      // 新增退款接口
      public interface IRefundablePayment : IPayment {
          RefundResult Refund(decimal amount);
      }
      
      // 只有支持退款的支付方式實現(xiàn)新接口
      public class CreditCardPayment : IRefundablePayment {
          private string _lastTransactionId;
          
          public PaymentResult Execute(decimal amount) {
              // 處理支付并記錄交易ID
              _lastTransactionId = "tx_" + Guid.NewGuid().ToString();
              return new PaymentResult { Success = true };
          }
          
          public RefundResult Refund(decimal amount) {
              // 使用交易ID處理退款
              return new RefundResult { Success = true };
          }
      }
      
      // 不支持退款的支付方式不需要變更
      public class GiftCardPayment : IPayment {
          public PaymentResult Execute(decimal amount) {
              // 禮品卡支付
              return new PaymentResult { Success = true };
          }
      }

       

      狀態(tài)管理

      IPaymentProcessor 沒有合適的狀態(tài)管理位置

      // 處理器沒有內(nèi)部狀態(tài)
      public class CreditCardPaymentProcessor : IPaymentProcessor {
          // 狀態(tài)必須在外部管理
          public void ProcessPayment(decimal amount) {
              // 從哪里獲取卡號和有效期?
              
          }
      }

       

      IPayment:狀態(tài)自然封裝

      // 支付對象封裝所需的所有狀態(tài)
      public class CreditCardPayment : IPayment {
          private readonly string _cardNumber;
          private readonly string _expiryDate;
          
          public CreditCardPayment(string cardNumber, string expiryDate) {
              _cardNumber = cardNumber;
              _expiryDate = expiryDate;
          }
          
          public PaymentResult Execute(decimal amount) {
              // 直接使用內(nèi)部保存的狀態(tài)
              return ProcessCreditCardPayment(_cardNumber, _expiryDate, amount);
          }
      }
      
      // 使用代碼簡潔明了
      public void CheckoutCart(ShoppingCart cart, CustomerInput input) {
          var payment = new CreditCardPayment(input.CardNumber, input.ExpiryDate);
          var result = payment.Execute(cart.Total);
      }

       

      小結(jié)

      對象命名是軟件工程中最基礎(chǔ)也最重要的環(huán)節(jié)之一。遵循"以事物本質(zhì)命名,而非事物功能"的原則,能夠創(chuàng)建更清晰、更穩(wěn)定、更易于理解和維護的代碼。

      一個簡單的辦法是,在日常開發(fā)中遇到使用"er"/"or"結(jié)尾的對象命名時,需要引起警覺,考慮如何使用反映領(lǐng)域?qū)嶓w本質(zhì)的命名方式。

       

      posted @ 2025-03-20 08:25  CareySon  閱讀(2280)  評論(31)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品一区二区三天美| 久久波多野结衣av| 久热在线中文字幕色999舞| 五月婷婷久久中文字幕| 久久99精品久久久久久不卡| 亚洲综合黄色的在线观看| 国内精品自线在拍| 99久久夜色精品国产亚洲| 久久精品国产亚洲av麻豆长发| 色偷偷www.8888在线观看| 亚洲一区二区三区丝袜| 噜噜噜亚洲色成人网站∨| 日本丰满人妻xxxxxhd| 91孕妇精品一区二区三区| 久久欧洲精品成av人片| 山东省| 精品国产乱来一区二区三区| 男女性高爱潮免费网站| 福利成人午夜国产一区| gogogo在线播放中国| 精品无码久久久久国产动漫3d| 国产一区二区三区色噜噜| 坐盗市亚洲综合一二三区| 国产成人精彩在线视频| 一区二区不卡国产精品| 久热这里只有精品视频3| 国产初高中生粉嫩无套第一次| 亚洲精品一区二区三区婷婷月| 无码成人精品区在线观看| 国产精品久久国产精麻豆| 亚洲av成人免费在线| 日韩人妻中文字幕精品| 日本狂喷奶水在线播放212| 精品午夜福利短视频一区| 精品国产成人国产在线视| 色偷偷亚洲男人的天堂| 亚洲精品国产精品国在线| av中文字幕国产精品| 婷婷色爱区综合五月激情韩国| 国产精品人妻| 一本大道久久香蕉成人网|