重构改善既有代码设计--重构手法11:Move Field (搬移字段)
你的程序中,某個字段被其所駐類之外的另一個類更多的用到。在目標類建立一個新字段,修改源字段的所有用戶,令它們改用新字段。
???????動機:在類之間移動狀態和行為,是重構過程中必不可少的措施。隨著系統發展,你會發現自己需要新的類,并需要將現有的工作責任拖到新的類中。在這個星期看似合理而正確的設計決策,到了下個星期可能不再正確。這沒問題,如果你從來沒遇到這種情況,那才有問題。
???????如果發現對于一個字段,在其所駐類之外的另一個類中有更多函數使用了它,就考慮搬移這個字段。上述所謂“使用”可能是通過設值/取值函數間接進行的。也可能移動該字段的用戶(某個函數),這取決于是否需要保持接口不受變化。如果這些函數看上去很適合待在原地,就選擇搬移字段。
???????使用Extract Class (提煉類)時,也可能需要搬移字段。此時可以先搬移字段,然后搬移函數。
做法:1、如果字段的訪問級別是public,使用 Encapsulated Field (封裝字段)將它們封裝起來。如果你有可能移動那些頻繁訪問該字段的函數,或如果有許多函數訪問某個字段,先使用 Self Encapsulate Field (自封裝字段)也許會有幫助。
????? 2、編譯、測試。
????? 3、在目標類中建立于源字段相同的字段,并同時建立相應的設值/取值函數。
????? 4、編譯目標類。
????? 5、決定如何在源對象中引用目標對象。首先看是否有一個現成的字段或函數可以助你得到目標對象。如果沒有,就看能否輕易建立這樣一個函數。如果還不行,就得在源類中新建一個字段來存放目標對象。這可能是個永久性修改,但你也可以讓它是暫時的。因為后續重構可能會把這個新建字段除掉。
????? 6、刪除源字段。
????? 7、將所有對源字段的引用替換為某個目標函數的調用。如果需要讀取該變量,就把對源字段的引用替換為對設值函數的調用。如果源字段不是private的,就必須在源類的所有子類中查找源字段的引用點,并進行相應替換。
???? 8、編譯、測試。
?
下面是Account class的部分代碼:
class Account...
??? private AccountType _type;
??? private double _interestRate;
??? double interestForAmount_days(double amount, int days) {
?????? return _interestRate * amount * days / 365;
??? }
?
我想把表示利率的_interestRate搬移到AccountType?class去。目前已有數個函數引用了它,interestForAmount_days()就是其一。下一步我要在AccountType中建立_interestRate field以及相應的訪問函數:
class AccountType...
??? private double _interestRate;
??? void setInterestRate(double arg) {
?????? _interestRate = arg;
??? }
??? double getInterestRate() {
?????? return _interestRate;
??? }
?
這時候我可以編譯新的?AccountType?class。
現在,我需要讓Account class中訪問_interestRate field的函數轉而使用AccountType對象,然后刪除Account class中的_interestRate field。我必須刪除source field,才能保證其訪問函數的確改變了操作對象,因為編譯器會幫我指出未正確獲得修改的函數。
class Account...
??? private double _interestRate;
??? double interestForAmount_days(double amount, int days) {
??? ?? return?_type.getInterestRate()?* amount * days / 365;
??? }
?
如果有很多函數已經使用了_interestRate field,我應該先運用Self Encapsulate Field(171):
class Account...
??? private AccountType _type;
??? private double _interestRate;
??? double interestForAmount_days(double amount, int days) {
?????? return getInterestRate() * amount * days / 365;
??? }
??? private void setInterestRate(double arg) {
?????? _interestRate = arg;
??? }
??? private double getInterestRate() {
?????? return _interestRate;
??? }
?
這樣,在搬移field之后,我就只需要修改訪問函數就行了:
??? double interestForAmount_days(double amount, int days) {
?????? return getInterestRate() * amount * days / 365;
??? }
??? private void setInterestRate(double arg) {
?????? _type.setInterestRate(arg);
??? }
??? private double getInterestRate() {
?????? return _type.getInterestRate();
??? }
?
如果以后有必要,我可以修改訪問函數(accessors)的用戶,讓它們使用新對象。Self Encapsulate Field(171)使我得以保持小步前進。如果我需要對class做許多處理,保持小步前進是有幫助的。特別值得一提的是:首先使用Self Encapsulate Field(171)使我得以更輕松使用Move Method(142)將函數搬移到target class中。如果待移函數引用了field的訪問函數(accessors),那么那些引用點是無須修改的。
轉載于:https://www.cnblogs.com/pony1223/p/7530450.html
總結
以上是生活随笔為你收集整理的重构改善既有代码设计--重构手法11:Move Field (搬移字段)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 泛型与反射
- 下一篇: springboot profiles