重构--改善既有代码的设计--读书笔记1

    技术2024-07-07  72

      

    重构--改善既有代码的设计--读书笔记1

    看了第一章的,敲出了所有的代码,共4版,自己理解写的比较少。以后慢慢在以后各章中补充吧。第一章看的还算顺利,可能代码太少了,还体会不深。

     

    ver1

    package Refactoring_Impr; import java.util.Enumeration; import java.util.Vector; public class C1_ver1 { class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private int _priceCode; public Movie(String title, int priceCode) { _title = title; _priceCode = priceCode; } public int getPriceCode() { return _priceCode; } public void setPriceCode(int arg) { _priceCode = arg; } public String getTitle() { return _title; }; } class Rental { private Movie _movie; private int _daysRented; public Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } public int getDaysRented() { return _daysRented; } public Movie getMovie() { return _movie; } } class Customer { private String _name; private Vector<Rental> _rentals = new Vector<Rental>(); public Customer(String name) { _name = name; }; public void addRental(Rental arg) { _rentals.addElement(arg); } public String getName() { return _name; } public String statement() { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration<Rental> rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "/n"; while (rentals.hasMoreElements()) { double thisAmount = 0; Rental each = (Rental) rentals.nextElement(); // determine amounts for each line switch (each.getMovie().getPriceCode()) { case Movie.REGULAR: thisAmount += 2; if (each.getDaysRented() > 2) thisAmount += (each.getDaysRented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisAmount += each.getDaysRented() * 3; break; case Movie.CHILDRENS: thisAmount += 1.5; if (each.getDaysRented() > 3) thisAmount += (each.getDaysRented() - 3) * 1.5; break; } // add frequent renter points frequentRenterPoints++; // add bonus for a two day new release rental if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) frequentRenterPoints++; // show figures for this rental result += "/t" + each.getMovie().getTitle() + "/t" + String.valueOf(thisAmount) + "/n"; totalAmount += thisAmount; } // add footer lines result += "Amount owed is " + String.valueOf(totalAmount) + "/n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } } }

    提取出accountFor()

     

    拿到第一版本的代码,首先第一印象是statement()函数太长了。将长函数切分为几个短函数,当有新的功能函数需要实现时更好重用。

    运用Extract Method提取switch代码段。

    在大函数里面的局部变量,不会被修改的可以作为新的小函数的入参。

     

    重构技术以微小的步伐前进,方便查错。

     

    accountFor()移到到Rental类中,因为他只用到了Rental中的信息。

    使用了委托测试新修改后的代码。

     

    移去原有的多余临时变量thisAccount,改成rental.getCharge(),这涉及到了重构与性能的问题。(P69会再讨论) Replace temp with query 

     

    提取常客积点代码

    点数计算的方式只与影片的类型有关。变化不会很多,先放到Rental中。

    ver2

    package Refactoring_Impr; import java.util.Enumeration; import java.util.Vector; public class C1_ver2 { class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private int _priceCode; public Movie(String title, int priceCode) { _title = title; _priceCode = priceCode; } public int getPriceCode() { return _priceCode; } public void setPriceCode(int arg) { _priceCode = arg; } public String getTitle() { return _title; }; } class Rental { private Movie _movie; private int _daysRented; public Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } public int getDaysRented() { return _daysRented; } public Movie getMovie() { return _movie; } public int getFrequentRenterPoints() { if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1) return 2; else return 1; } public double getCharge() { double result = 0; switch (getMovie().getPriceCode()) { case Movie.REGULAR: result += 2; if (getDaysRented() > 2) result += (getDaysRented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += getDaysRented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (getDaysRented() > 3) result += (getDaysRented() - 3) * 1.5; break; } return result; } } class Customer { private String _name; private Vector<Rental> _rentals = new Vector<Rental>(); public Customer(String name) { _name = name; }; public void addRental(Rental arg) { _rentals.addElement(arg); } public String getName() { return _name; } public String statement() { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration<Rental> rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "/n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); frequentRenterPoints += each.getFrequentRenterPoints(); // show figures for this rental result += "/t" + each.getMovie().getTitle() + "/t" + String.valueOf(each.getCharge()) + "/n"; totalAmount += each.getCharge(); } // add footer lines result += "Amount owed is " + String.valueOf(totalAmount) + "/n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } } }

    去除临时变量,totalAmountfrequentRenterPoints这两个临时变量

    这样多带来了2次循环,但是提取成函数可以增加复用性。有利有弊

    增加了一个htmlStatement()函数证明这点

     

    多态取代switch

    null

    ver3

    package Refactoring_Impr; import java.util.Enumeration; import java.util.Vector; public class C1_ver3 { class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private int _priceCode; public Movie(String title, int priceCode) { _title = title; _priceCode = priceCode; } public int getPriceCode() { return _priceCode; } public String getTitle() { return _title; } public int getFrequentRenterPoints(int daysRented) { if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1) return 2; else return 1; } double getCharge(int daysRented) { double result = 0; switch (getPriceCode()) { case Movie.REGULAR: result += 2; if (daysRented > 2) result += (daysRented - 2) * 1.5; break; case Movie.NEW_RELEASE: result += daysRented * 3; break; case Movie.CHILDRENS: result += 1.5; if (daysRented > 3) result += (daysRented - 3) * 1.5; break; } return result; } } class Rental { private Movie _movie; private int _daysRented; public Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } public Movie getMovie() { return _movie; } public int getFrequentRenterPoints() { return _movie.getFrequentRenterPoints(_daysRented); } public double getCharge() { return _movie.getCharge(_daysRented); } } class Customer { private String _name; private Vector<Rental> _rentals = new Vector<Rental>(); public Customer(String name) { _name = name; }; public void addRental(Rental arg) { _rentals.addElement(arg); } public String getName() { return _name; } public String statement() { Enumeration<Rental> rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "/n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); // show figures for this rental result += "/t" + each.getMovie().getTitle() + "/t" + String.valueOf(each.getCharge()) + "/n"; } // add footer lines result += "Amount owed is " + String.valueOf(getTotalCharge()) + "/n"; result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points"; return result; } public String htmlStatement() { Enumeration<Rental> rentals = _rentals.elements(); String result = "<H1>Rentals for <EM>" + getName() + "</EM></H1><P>/n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); // show figures for each rental result += each.getMovie().getTitle() + ": " + String.valueOf(each.getCharge()) + "<BR>/n"; } // add footer lines result += "<P>You owe <EM>" + String.valueOf(getTotalCharge()) + "</EM><P>/n"; result += "On this rental you earned <EM>" + String.valueOf(getTotalFrequentRenterPoints()) + "</EM> frequent renter points<P>"; return result; } private double getTotalCharge() { double result = 0; Enumeration<Rental> rentals = _rentals.elements(); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getCharge(); } return result; } private int getTotalFrequentRenterPoints() { int result = 0; Enumeration<Rental> rentals = _rentals.elements(); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getFrequentRenterPoints(); } return result; } } }

    继承

    因为影片类型变化较大,且他们就好像在回答一种问题。采用继承体系。

    ver4

    package Refactoring_Impr; import java.util.Enumeration; import java.util.Vector; import Refactoring_Impr.C1_ver2.Rental; public class C1_ver4 { class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private Price _price; public Movie(String title, int priceCode) { _title = title; setPriceCode(priceCode); } public double getCharge(int daysRented) { return _price.getCharge(daysRented); } int getFrequentRenterPoints(int daysRented) { return _price.getFrequentRenterPoints(daysRented); } public void setPriceCode(int arg) { switch (arg) { case REGULAR: _price = new RegularPrice(); break; case CHILDRENS: _price = new ChildrensPrice(); break; case NEW_RELEASE: _price = new NewReleasePrice(); break; default: throw new IllegalArgumentException("Incorrect Price Code"); } } public String getTitle() { return _title; }; } abstract class Price { abstract double getCharge(int daysRented); int getFrequentRenterPoints(int daysRented) { return 1; } } class ChildrensPrice extends Price { double getCharge(int daysRented) { double result = 1.5; if (daysRented > 3) result += (daysRented - 3) * 1.5; return result; } } class NewReleasePrice extends Price { double getCharge(int daysRented) { return daysRented * 3; } int getFrequentRenterPoints(int daysRented) { return (daysRented > 1) ? 2 : 1; } } class RegularPrice extends Price { double getCharge(int daysRented) { double result = 2; if (daysRented > 2) result += (daysRented - 2) * 1.5; return result; } } class Rental { private Movie _movie; private int _daysRented; public Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } public int getDaysRented() { return _daysRented; } public Movie getMovie() { return _movie; } public int getFrequentRenterPoints() { return _movie.getFrequentRenterPoints(_daysRented); } public double getCharge() { return _movie.getCharge(_daysRented); } } class Customer { private String _name; private Vector<Rental> _rentals = new Vector<Rental>(); public Customer(String name) { _name = name; }; public void addRental(Rental arg) { _rentals.addElement(arg); } public String getName() { return _name; } public String statement() { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration<Rental> rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "/n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); frequentRenterPoints += each.getFrequentRenterPoints(); // show figures for this rental result += "/t" + each.getMovie().getTitle() + "/t" + String.valueOf(each.getCharge()) + "/n"; totalAmount += each.getCharge(); } // add footer lines result += "Amount owed is " + String.valueOf(totalAmount) + "/n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } } }

     

    最新回复(0)