隨筆 - 3, 文章 - 152, 評論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          TDD(2) --轉(zhuǎn)自http://www.aygfsteel.com/yandazhi

          重構(gòu)以兩種方式和TDD密切相關(guān)。

          在以盡可能簡單的手段通過測試之后,(在這個過程中違反了任何編碼規(guī)則)我們就進行重構(gòu)清理。大部分是除去我們?yōu)榱送ㄟ^測試而帶來的重復(fù)。

          如果我們是按TDD行事,那么我們就有了適當(dāng)?shù)臏y試的安全網(wǎng),這使得我們有信心進行重構(gòu)。   

          何時重構(gòu)?

          1  重復(fù)的時候

          public boolean save() throws IOException {
            
          if (outputFile == null{
              
          return false;
            }


            FileWriter writer 
          = new FileWriter(outputFile);
            movies.writeTo(writer);
            writer.close();
            
          return true;
          }


          public boolean saveAs() throws IOException {
            outputFile 
          = view.getFile();
            
          if (outputFile == null{
              
          return false;
            }


            FileWriter writer 
          = new FileWriter(outputFile);
            movies.writeTo(writer);
            writer.close();
            
          return true;
          }


          替代成

          public boolean saveAs() throws IOException {
            outputFile 
          = view.getFile();
            save();
          }


          2  我們發(fā)現(xiàn)代碼,或者/并且它的意圖不清楚的時候。、

          代碼是最重要的交付產(chǎn)品,必須盡可能清楚和可理解。

          3  我們嗅到代碼味道,微妙的(或者不那么微妙的)跡象表明代碼有問題。

          代碼味道不一定總是表明有問題,但是代碼味道表明我們應(yīng)該仔細察看一下,是否有問題。

          如何重構(gòu)?

          析取類
          看看下面的例子

          public void writeTo(Writer destination) throws IOException {
            Iterator movieIterator 
          = movies.iterator();
            
          while (movieIterator.hasNext()) {
              Movie movieToWrite 
          = (Movie)movieIterator.next();;
              destination.write(movieToWrite.getName());
              destination.write(
          '|');
              destination.write(movieToWrite.getCategory().toString());
              destination.write(
          '|');

              
          try {
                destination.write(Integer.toString(movieToWrite.getRating()));
              } 
          catch (UnratedException ex) {
                destination.write(
          "-1");
              }
              destination.write(
          '\n');
            }
          }

          MovieList不恰當(dāng)?shù)陌颂郙ovie的特性


          public class MovieList {
            
          //
            public void writeTo(Writer destination) throws IOException {
              Iterator movieIterator 
          = movies.iterator();
              
          while (movieIterator.hasNext()) {
                Movie movieToWrite 
          =(Movie)movieIterator.next();;
                movieToWrite.writeTo(destination);
              }
          }

          public classMovie {
            
          //

            
          public void writeTo(Writer destination) {
              destination.write(getName());
              destination.write(
          '|');
              destination.write(getCategory(). toString());
              destination.write(
          '|');c

              
          try {
                destination.write(Integer.toString(getRating()));

              } 
          catch (UnratedException ex) {
                destination.write(
          "-1");
              }

              destination.write(
          '\n');
            }
          }


           寫電影列表的工作放在MovieList和Movie當(dāng)中,應(yīng)該抽象出來。

          public class MovieListWriter 
          {
            Writer destination 
          = null;

            
          public MovieListWriter(Writer aWriter) {
              destination 
          = aWriter;
            }

            
          public void writeMovieList(MovieList aList) throws IOException {
              Iterator movieIterator 
          = aList.getMovies().iterator();
              
          while (movieIterator.hasNext()) {
                Movie movieToWrite 
          = (Movie)movieIterator.next();;
                writeMovie(movieToWrite);
              }

            
          private void writeMovie(Movie aMovie) {
              destination.write(aMovie.getName());
              destination.write(
          '|');
              destination.write(aMovie.getCategory().toString());
              destination.write(
          '|');

              
          try {
                destination.write(Integer.toString(aMovie.getRating()));

              } 
          catch (UnratedException ex) {
                destination.write(
          "-1");
              }
              destination.write(
          '\n');
            }
          }


          寫電影列表的代碼集中起來。而且只有writeMovieList()方法暴露出來,其他的細節(jié)都封裝起來。

          析取接口

          下面是一個有形的類,非常簡單
          public class MovieList {
            
          private Collection movies = new ArrayList();


            
          public int size() {
              
          return movies.size();
            }

            
          public void add(Movie movieToAdd) {
              movies.add(movieToAdd);
            }

            
          public boolean contains(Movie movieToCheckFor) {
              
          return movies.contains(movieToCheckFor);
            }
          }

          如果需要模擬他,我們應(yīng)該析取接口

          public interface IMovieList {
            
          int size();
            
          void add(Movie movieToAdd);
            boolean contains(Movie movieToCheckFor);
          }




          public class MovieList implements IMovieList {
            
          //
          }


          析取方法

          過于龐大的方法,應(yīng)該進行拆分。下面的方法,每個注釋出現(xiàn)的地方可以析取出來
          public void init() {
            
          // set the layout
            getContentPane().setLayout(new FlowLayout());

            
          // create the list
            movieList = new JList(myEditor.getMovies());
            JScrollPane scroller 
          = new JScrollPane(movieList);
            getContentPane().add(scroller);

            
          // create the field
            movieField = new JTextField(16);
            getContentPane().add(movieField);

            
          // create the add button
            addButton = new JButton("Add");
            addButton.addActionListener(
          new ActionListener() {
              
          public void actionPerformed(ActionEvent e) {
                myEditor.add(movieField.getText());
                movieList.setListData(myEditor.getMovies());
              }
            });
            getContentPane().add(addButton);
          }


          分解和命名為成一些不證自明的方法。

          public void init() {
            setLayout();
            initMovieList();
            initMovieField();
            initAddButton();
          }

          private void setLayout() {
            getContentPane().setLayout(
          new FlowLayout());
          }

          private void initMovieList() {
            movieList 
          = new JList(getMovies());
            JScrollPane scroller 
          = new JScrollPane(movieList);
            getContentPane().add(scroller);
          }

          private void initMovieField() {
            movieField 
          = new JTextField(16);
            getContentPane().add(movieField);
          }

          private void initAddButton() {
            addButton 
          = new JButton("Add");
            addButton.addActionListener(
          new ActionListener() {
              
          public void actionPerformed(ActionEvent e) {
                myEditor.add(movieField.getText());
                movieList.setListData(getMovies());
              }
            });
            getContentPane().add(addButton);
          }


          用子類代替類型代碼

          public class Employee {
            
          // 0 - engineer, 1 - salesman, 2 - manager
            private int employeeType;

            
          //..
            }


          替代成

          abstract public class Employee {
            
          //. . .
          }

          public class Engineer extends Employee {
            
          //. . .
          }

          public class Salesman extends Employee 
          {
            
          //. . .
          }

          public class Manager extends Employee 
          {
            
          //. . .
          }


          用多態(tài)來替代條件(開關(guān))語句

          public class Employee {
            
          // 0 - engineer, 1 - salesman, 2 - manager
            private int employeeType;

            
          public String departmentName() {
              
          switch (employeeType) {
                
          case 0:
                  
          return "Engineering";
                
          case 1:
                  
          return "Sales";
                
          case 2:
                  
          return "Management";
                
          default:
                  
          return "Unknown";
              }
            }
          }


          替代為
          abstract public class Employee {
            
          public abstract String departmentName();
          }


          public class Engineer extends Employee {
            
          public String departmentName() {
              
          return "Engineering";
            }
          }


          public class Salesman extends Employee {
            
          public String departmentName() {
              
          return "Sales";
          }
          }


          public class Manager extends Employee {
            
          public String departmentName() {
              
          return "Management";
            }
          }


          模板方法

          public class Engineer extends Employee {
            
          public String asXML() {
              StringBuffer buf 
          = new StringBuffer();
              buf.append(
          "<employee name=\"");
              buf.append(getName());
              buf.append(
          "\" department=\"Engineering\">");
              //
              return buf.toString();
            }
            
          //. . .
          }





          public class Salesman extends Employee {
            
          public String asXML() {
              StringBufer buf 
          = new StringBuffer();
              buf.append(
          "<employee name=\"");
              buf.append(getName());
              buf.append(
          "\" department=\"Sales\">");
              //. . .
              return buf.toString();
            }
            
          //
          }


          public class Manager extends Employee {
            
          public String asXML() {
              StringBufer buf 
          = new StringBuffer();
              buf.append(
          "<employee name=\"");
              buf.append(getName());
              buf.append(
          "\" department=\"Management\">");
              //. . .
              return buf.toString();
            }
            
          //
          }


          用employee很好地解決了問題

          public class Employee {
            
          public String asXML() {
              StringBuffer buf 
          = new StringBuffer();
              buf.append(
          "<employee name=\"");
              buf.append(getName());
              buf.append(
          "\" department=\"");
              buf.append(departmentName());
              buf.append(
          "\">");
              //
              return buf.toString();
            }
            
          //. . .
          }



          引入解釋變量

          public Money calculateTotal() {
            
          return getSubtotal().plus((getTaxableSubtotal().times(0.15))).minus((getSubtotal().asDouble()> 100.0)?(getSubtotal().times(0.10)):0);

          public Money calculateTotal() {
            Money subtotal 
          = getSubtotal();
            Money tax 
          = getTaxableSubtotal().times(0.15);
            Money total 
          =subtotal.plus(tax);
            boolean qualifiesForDiscount 
          = getSubtotal().asDouble() 
          > 100.0;
            Money discount 
          = qualifiesForDiscount
                                   
          ?subtotal.times(0.10)
                                   :newMoney(
          0.0);
            
          return total.minus(discount);

          用工廠方法替代構(gòu)造函數(shù)

          public classRating {
            
          private int value = 0;
            
          private String source = null;
            
          private String review = null;

            
          public Rating(int aRating) {
              
          this(aRating, "Anonymous""");
            }

            
          public Rating(int aRating, String aRatingSource) {
              
          this(aRating, aRatingSource, "");
            }

            
          public Rating(int aRating, String aRatingSource, String aReview) {
              value 
          = aRating;
              source 
          = aRatingSource;
              review 
          = aReview;
            }

            
          //
          }



          public static Rating newAnonymousRating(int value) {
            
          return new Rating(value, "Anonymous""");
          }

          public static Rating newRating(int value, String source) {
            
          return new Rating(value, source, "");
          }

          public static Rating newReview(int value, String source, String review) {
            
          return new Rating(value, source, review);
          }

          private Rating(int aRating, String aRatingSource, String aReview) {
            value 
          = aRating;
            source 
          = aRatingSource;
            review 
          = aReview;
          }


          用代理代替繼承

          public class Department extends Vector {
          }

          public class Department {
            
          private Vector employees = new Vector();

            
          public void hire(Employee newHire) {
              employees.add(newHire);
            }

            
          public DepartmentIterator iterator() {
              
          return new DepartmentIterator();
            }

            
          public class DepartmentIterator {
              Iterator underlying 
          = employees.iterator();

              
          public boolean hasNext() {
                
          return underlying.hasNext();
              }

              
          public Employee next() {
                
          return (Employee)underlying.next();
              }
            }
          }


          posted on 2005-07-25 12:26 閱讀(239) 評論(0)  編輯  收藏 所屬分類: Test-Driven Development

          主站蜘蛛池模板: 扶风县| 民勤县| 图木舒克市| 平谷区| 旌德县| 井陉县| 阳江市| 天峻县| 嘉荫县| 安丘市| 博乐市| 遵化市| 耿马| 瓦房店市| 昌邑市| 商都县| 冀州市| 屏东县| 庄浪县| 石渠县| 新化县| 安阳市| 民县| 客服| 丹棱县| 长乐市| 江达县| 信阳市| 东城区| 松江区| 都江堰市| 涞水县| 乐业县| 清镇市| 左云县| 兴安县| 荥经县| 墨竹工卡县| 晋城| 策勒县| 申扎县|