隨筆 - 3, 文章 - 152, 評論 - 17, 引用 - 0

          導航

          公告

          歡迎來到辰的blog

          發消息給我有事您Q我

          常用鏈接

          文章分類(153)

          搜索

          •  

          積分與排名

          • 積分 - 52853
          • 排名 - 951

          最新評論

          閱讀排行榜

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

          重構以兩種方式和TDD密切相關。

          在以盡可能簡單的手段通過測試之后,(在這個過程中違反了任何編碼規則)我們就進行重構清理。大部分是除去我們為了通過測試而帶來的重復。

          如果我們是按TDD行事,那么我們就有了適當的測試的安全網,這使得我們有信心進行重構。   

          何時重構?

          1  重復的時候

          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  我們發現代碼,或者/并且它的意圖不清楚的時候。、

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

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

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

          如何重構?

          析取類
          看看下面的例子

          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不恰當的包含了太多Movie的特性


          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當中,應該抽象出來。

          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()方法暴露出來,其他的細節都封裝起來。

          析取接口

          下面是一個有形的類,非常簡單
          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);
            }
          }

          如果需要模擬他,我們應該析取接口

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




          public class MovieList implements IMovieList {
            
          //
          }


          析取方法

          過于龐大的方法,應該進行拆分。下面的方法,每個注釋出現的地方可以析取出來
          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 
          {
            
          //. . .
          }


          用多態來替代條件(開關)語句

          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);

          用工廠方法替代構造函數

          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 閱讀(240) 評論(0)  編輯  收藏 所屬分類: Test-Driven Development

          主站蜘蛛池模板: 信宜市| 富蕴县| 乌拉特后旗| 乌鲁木齐市| 邹平县| 嘉义市| 双柏县| 台前县| 长宁区| 兴隆县| 景洪市| 志丹县| 锡林浩特市| 长垣县| 夏邑县| 宁乡县| 麻阳| 祁连县| 呼伦贝尔市| 灵寿县| 资中县| 博白县| 光山县| 博野县| 拉萨市| 佛冈县| 衡东县| 四平市| 哈密市| 宜阳县| 紫云| 南靖县| 南郑县| 鄂尔多斯市| 惠东县| 峨眉山市| 无极县| 闸北区| 马鞍山市| 龙口市| 胶州市|