最新公告
  • 欢迎您光临波比源码,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • 《重构》第一章示例 ― 体验重构的魔力 RefactorSample

           实验室已坐定了,环境和氛围很好,今天老师请来了北京卓尔的孙经理,聊了很多,最大的意外是,任老师是云计算出身,棒,java以后必定是要接触云计算的。

    1个月了,没有认真写博客,也没有认真学习,数据库的学习进度1直拖拖拉拉到现在也没有弄定,sad。。。接了1个任务,写1个基于Web的实验室内部的管理系统,拿来练手,以后就是企业项目1个CC呼唤中心的1模块,对接卓尔,第1次接触实际项目,还甚么都不会,激动却又忐忑。但,再1起重新燃起了学习的热火,来吧。


    今天,看了1下《重构》的第1章,深深的被吸引了….

    Let‘s go,1起走进重构的世界吧!


    示例 

    情形:顾客租电影,电影分3种,儿童票,普通片,新片,儿童片2天之内1.5元,超过两天,每天加收1.5元,普通片3天之内2元,超过两天,每天加收2元,新片每天3元,每租1次电影积分加1,如果是新片,且租期超过2天,积分加2。

    分析:

    以面向对象的思想分析,触及对象顾客,影片,外加1个租赁类作为顾客和影片的桥接

    编写代码

    影片类(Movie):

    public class Movie {
    public static final int CHILDRENS = 0;
    public static final int REGULARS = 1;
    public static final int NEW_RELEASE = 2;
    private String name;
    private int movType;

    public Movie(String name, int movType) {
    this.name = name;
    this.movType = movType;
    }

    name: set 和 get 方法
    movType: set 和get 方法
    }

    为了节省篇幅,Movie类的name、movType的set和get就不贴了。

    租赁类(Rental):

    public class Rental {
    private Movie movie;
    private int rentDays;

    public Rental(Movie movie,int rentDays) {
    this.movie = movie; this.rentDays = rentDays;
    }

    movie 和 rentDays的set和get方法


    顾客类(Customer):

    public class Customer {
    private String name;
    private ArrayList<Rental> rentals = new ArrayList<Rental>();

    public Customer(String name) {
    this.name = name;
    }
    public void addRent(Rental r){
    rentals.add(r);
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String statement() throws Exception {
    String result = "Rental report for " + getName() + "
    ";
    double totalAmount = 0;
    int frequent = 0;
    for(Rental r : rentals){
    double thisAmount = 0;
    switch (r.getMovie().getMovType()){
    case Movie.CHILDRENS :
    thisAmount += (r.getRentDays()>2)?((r.getRentDays()⑵)*1.5+1.5):1.5;
    break;
    case Movie.REGULARS:
    thisAmount += (r.getRentDays()>3)?((r.getRentDays()⑶)*2+2):2;
    break;
    case Movie.NEW_RELEASE:
    thisAmount += r.getRentDays() * 3;
    break;
    default:throw new Exception("类型异常");

    }
    totalAmount += thisAmount;
    frequent += (r.getMovie().getMovType()==Movie.NEW_RELEASE &&
    r.getRentDays()>2)?2:1;
    result+=" " + r.getMovie().getName() + " " + String.valueOf(thisAmount) + "
    ";
    }
    result += "Amount is " + String.valueOf(totalAmount) + "元
    ";
    result += "frequent is " + String.valueOf(frequent)+"分";
    return result;
    }
    }

    编写测试代码:

    public class Test {
    public static void main(String[] args) throws Exception {
    Movie m1 = new Movie("葫芦娃",0);//儿童片
    Movie m2 = new Movie("神雕侠侣",1);//普通片
    Movie m3 = new Movie("何以笙箫默",2);//新片
    Customer c = new Customer("朱小妹");
    c.addRent(new Rental(m1,2));//1.5
    c.addRent(new Rental(m2,2));//2
    c.addRent(new Rental(m3,3));//9
    System.out.println(c.statement());
    }
    }

    以上代码完成了示例需求,但是代码写的…太烂了,我自己写绝对也是这个模样。。。代码烂,怎样办?重构!

    第1步:1劳永逸 ―  修改测试代码


    为了方便测试,我们将打印结果作为1个字符串保存起来。

    public class Test {
    public static void main(String[] args) throws Exception {
    Movie m1 = new Movie("葫芦娃",0);//儿童片
    Movie m2 = new Movie("神雕侠侣",1);//普通片
    Movie m3 = new Movie("何以笙箫默",2);//新片
    Customer c = new Customer("朱小妹");
    c.addRent(new Rental(m1,2));//1.5
    c.addRent(new Rental(m2,2));//2
    c.addRent(new Rental(m3,3));//9
    String result = "Rental report for 朱小妹
    " +
    " 葫芦娃 1.5
    " +
    " 神雕侠侣 2.0
    " +
    " 何以笙箫默 9.0
    " +
    "Amount is 12.5元
    " +
    "frequent is 4分";
    System.out.println(c.statement().equals(result));
    }
    }

    以后的测试结果,true就是修改正确,false就是修改失败。


    第2步:1石2鸟  ―  分解customer类statement方法


    纵观所有代码,惟独customer类的statement代码最多,最乱,看着烦,看switch更烦,而switch的作用就是1个计算1个临时变量thisAmount的作用,而临时变量越多对1个程序来讲就越容易出错,既然容易出错,totalAmount和frement有甚么用,还占地方,留它们干吗,拿走,单独封装。

    更改后的customer类:

    public class Customer {
    private String name;
    private ArrayList<Rental> rentals = new ArrayList<Rental>();

    public Customer(String name) {
    this.name = name;
    }
    public void addRent(Rental r){
    rentals.add(r);
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String statement() throws Exception {
    String result = "Rental report for " + getName() + "
    ";
    for (Rental r : rentals ) {
    result += " " + r.getMovie().getName() + " " + String.valueOf(amountFor(r)) + "
    ";
    }
    result += "Amount is " + String.valueOf(getTotalAmount()) + "元
    ";
    result += "frequent is " + String.valueOf(getTotalFrequent())+"分";
    return result;
    }
    private double getTotalAmount() throws Exception {
    double totalAmount = 0;
    for(Rental r : rentals){
    totalAmount += amountFor(r);
    }
    return totalAmount;
    }
    private int getTotalFrequent(){
    int frequent = 0;
    for(Rental r : rentals){
    frequent += (r.getMovie().getMovType()==Movie.NEW_RELEASE &&
    r.getRentDays()>2)?2:1;
    }
    return frequent;
    }
    private double amountFor(Rental r) throws Exception {
    double thisAmount = 0;
    switch (r.getMovie().getMovType()){
    case Movie.CHILDRENS :
    thisAmount += (r.getRentDays()>2)?((r.getRentDays()⑵)*1.5+1.5):1.5;
    break;
    case Movie.REGULARS:
    thisAmount += (r.getRentDays()>3)?((r.getRentDays()⑶)*2+2):2;
    break;
    case Movie.NEW_RELEASE:
    thisAmount += r.getRentDays() * 3;
    break;
    default:throw new Exception("类型异常");
    }
    return thisAmount;
    }
    }

    这样statement方法庞大和临时变量多的问题都解决了,进行测试,true,修改正确

    第3步:各回各家 ― 做自己该干的事


    重新审视1下customer类,你会发现它很多它不该干的事,switch计算单次租赁花费和积分这个事,应当电影类干吧,花多钱,很多少分,电影本身最清楚

    问题还是存在switch身上,最好不要在另外一个对象的属性基础上应用switch,如果非要使用,也应当是在对象自己的数据上使用,而不是在他人的数据上使用。

    在rental类中增加getOneMoney方法和getOneFre方法,customer类删除amountFor方法,修改getTotalFrequent方法,switch搬家到Movie类中


    更改后的customer类

    只变动了getTotalFrequent方法for循环

    public class Customer {
    private String name;
    private ArrayList<Rental> rentals = new ArrayList<Rental>();

    public Customer(String name) {
    this.name = name;
    }
    public void addRent(Rental r){
    rentals.add(r);
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String statement() throws Exception {
    String result = "Rental report for " + getName() + "
    ";
    for (Rental r : rentals ) {
    result += " " + r.getMovie().getName() + " " + String.valueOf(r.getOne()) + "
    ";
    }
    result += "Amount is " + String.valueOf(getTotalAmount()) + "元
    ";
    result += "frequent is " + String.valueOf(getTotalFrequent())+"分";
    return result;
    }
    private double getTotalAmount() throws Exception {
    double totalAmount = 0;
    for(Rental r : rentals){
    totalAmount += r.getOne();
    }
    return totalAmount;
    }
    private int getTotalFrequent(){
    int frequent = 0;
    for(Rental r : rentals){
    frequent += r.getOneFre();
    }
    return frequent;
    }
    }


    更改后的rental,起了1个桥梁作用

    public class Rental {
    private Movie movie;
    private int rentDays;
    public Rental(Movie movie,int rentDays) {
    this.movie = movie; this.rentDays = rentDays;
    }
    public int getRentDays() {
    return rentDays;
    }
    public void setRentDays(int rentDays) {
    this.rentDays = rentDays;
    }
    public Movie getMovie() {

    return movie;
    }
    public double getOne() throws Exception {
    return getMovie().getMoney(rentDays) ;
    }
    public int getOneFre(){
    return getMovie().getFrequent(rentDays);
    }
    public void setMovie(Movie movie) {
    this.movie = movie;
    }
    }

    更改后的movie类,终究开始做事了

    /**
    * Created by Kevy on 2015/1/21.
    */
    /*编写电影类代码*/
    public class Movie {
    public static final int CHILDRENS = 0;
    public static final int REGULARS = 1;
    public static final int NEW_RELEASE = 2;
    private String name;
    private int movType;

    public Movie(String name, int movType) {
    this.name = name;
    this.movType = movType;
    }

    public int getMovType() {
    return movType;
    }
    public void setMovType(int movType) {
    this.movType = movType;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }

    public double getMoney(int RentDays) throws Exception {
    double thisAmount = 0;
    switch (getMovType()){
    case Movie.CHILDRENS :
    thisAmount += (RentDays>2)?((RentDays⑵)*1.5+1.5):1.5;
    break;
    case Movie.REGULARS:
    thisAmount += (RentDays>3)?((RentDays⑶)*2+2):2;
    break;
    case Movie.NEW_RELEASE:
    thisAmount += RentDays * 3;
    break;
    default:throw new Exception("类型异常");
    }
    return thisAmount ;
    }

    public int getFrequent(int RentDays){
    return (getMovType()==NEW_RELEASE &&
    RentDays>2)?2:1;
    }
    }

    测试OK,没有问题。


    第4步 利用多态

    现在所有的类,都在干自己的事,movie类的getMoney方法的代码量看着还是不太好,既然是3种电影只是类型不同而已,那末久完全可以向上抽取使用抽象类

    public interface Type {
    public int getType();
    public double getMovMeony(int days);
    }

    public class ChildrenMov implements Type {

    public int getType() {
    return 0;
    }

    public double getMovMeony(int days) {
    return (days>2)?((days⑵)*1.5+1.5):1.5;
    }
    }

    public class RegularMov implements Type {

    public int getType() {
    return 1;
    }

    public double getMovMeony(int days) {
    return (days>3)?((days⑶)*2+2):2;
    }
    }

    public class NewMov implements Type {
    public int getType() {
    return 2;
    }

    public double getMovMeony(int days) {
    return days * 3;
    }
    }

    终究完全代码:

    import java.util.ArrayList;

    /**
    * Created by Kevy on 2015/1/21.
    */
    public class Customer {
    private String name;
    private ArrayList<Rental> rentals = new ArrayList<Rental>();

    public Customer(String name) {
    this.name = name;
    }
    public void addRent(Rental r){
    rentals.add(r);
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String statement() throws Exception {
    String result = "Rental report for " + getName() + "
    ";
    for (Rental r : rentals ) {
    result += " " + r.getMovie().getName() + " " + String.valueOf(r.getOne()) + "
    ";
    }
    result += "Amount is " + String.valueOf(getTotalAmount()) + "元
    ";
    result += "frequent is " + String.valueOf(getTotalFrequent())+"分";
    return result;
    }
    private double getTotalAmount() throws Exception {
    double totalAmount = 0;
    for(Rental r : rentals){
    totalAmount += r.getOne();
    }
    return totalAmount;
    }
    private int getTotalFrequent(){
    int frequent = 0;
    for(Rental r : rentals){
    frequent += r.getOneFre();
    }
    return frequent;
    }
    }

    /**
    * Created by Kevy on 2015/1/21.
    */

    public class Rental {
    private Movie movie;
    private int rentDays;
    public Rental(Movie movie,int rentDays) {
    this.movie = movie; this.rentDays = rentDays;
    }
    public int getRentDays() {
    return rentDays;
    }
    public void setRentDays(int rentDays) {
    this.rentDays = rentDays;
    }
    public Movie getMovie() {

    return movie;
    }
    public double getOne() throws Exception {
    return getMovie().getMoney(rentDays) ;
    }
    public int getOneFre(){
    return getMovie().getFrequent(rentDays);
    }
    public void setMovie(Movie movie) {
    this.movie = movie;
    }
    }

    /**
    * Created by Kevy on 2015/1/21.
    */
    /*编写电影类代码*/
    public class Movie {
    public static final int CHILDRENS = 0;
    public static final int REGULARS = 1;
    public static final int NEW_RELEASE = 2;
    private String name;
    private Type t;

    public Movie(String name, int movType) throws Exception {
    this.name = name;
    setT(movType);
    }

    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }

    public double getMoney(int RentDays) {
    return t.getMovMeony(RentDays);
    }

    public int getFrequent(int RentDays){
    return (t.getType()==NEW_RELEASE &&
    RentDays>2)?2:1;
    }

    public void setT(int d) throws Exception {
    switch (d){
    case CHILDRENS :t = new ChildrenMov();
    break;
    case REGULARS:t = new RegularMov();
    break;
    case NEW_RELEASE:t = new NewMov();
    break;
    default:throw new Exception("类型毛病");
    }
    }
    }

    import sun.plugin2.message.ModalityChangeMessage;

    /**
    * Created by Kevy on 2015/1/21.
    */

    /* 编写测试代码 */
    public class Test {
    public static void main(String[] args) throws Exception {
    Movie m1 = new Movie("葫芦娃",0);//儿童片
    Movie m2 = new Movie("神雕侠侣",1);//普通片
    Movie m3 = new Movie("何以笙箫默",2);//新片
    Customer c = new Customer("朱小妹");
    c.addRent(new Rental(m1,2));//1.5
    c.addRent(new Rental(m2,2));//2
    c.addRent(new Rental(m3,3));//9
    String result = "Rental report for 朱小妹
    " +
    " 葫芦娃 1.5
    " +
    " 神雕侠侣 2.0
    " +
    " 何以笙箫默 9.0
    " +
    "Amount is 12.5元
    " +
    "frequent is 4分";
    System.out.println(c.statement().equals(result));

    }
    }

    至此,1个简单的代码重构示例,重构终了

    重构最大的启发就是:测试、小改、测试、小改….

    波比源码 – 精品源码模版分享 | www.bobi11.com
    1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
    2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
    3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
    4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
    5. 如有链接无法下载、失效或广告,请联系管理员处理!
    6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
    7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!

    波比源码 » 《重构》第一章示例 ― 体验重构的魔力 RefactorSample

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    波比源码
    一个高级程序员模板开发平台
    升级波友尊享更多特权立即升级