自学内容网 自学内容网

clean code-代码整洁之道 阅读笔记(第十六章)

第十六章 重构SerialDate

16.1 首先,让它能工作
  1. 利用SerialDateTests来完整的理解和重构SerialDate
  2. 用Clover来检查单元测试覆盖了哪些代码,效果不行
  3. 重新编写自己的单元测试
  4. 经过简单的修改,让测试能够通过
16.2 让它做对

全过程:

  1. 开端注释过时已久,缩短并改进了它
  2. 把全部枚举移到它们自己的文件
  3. 把静态变量(dateFormatSymbols)和3个静态方法(getMontShNames、isLeap Year和lastDayOfMonth)移到名为DateUtil的新类中。
  4. 把那些抽象方法上移到它们该在的顶层类中。
  5. 把Month.make改为Month.fromInt,并如法炮制所有其他枚举。为全部枚举创建了toInt()访问器,把index字段改为私有。
  6. 在plusYears和plusMonths中存在一些有趣的重复,通过抽离出名为
    correctLastDayOfMonth的新方法消解了重复,使这3个方法清晰多了。
  7. 消除了魔术数1,用Month.JANUARY.toInt()或Day.SUNDAY:toInt()做了恰当的替换。在SpreadsheetDate上花了点时间,清理了一下算法
     

细节操作:

  1. 删除修改历史
  2. 导入列表通过使用java.text.*和java.util.*来缩短
  3. 用<pre>标签把整个注释部分包围起来
  4. 修改类名:SerialDate => DayDate
  5. 把MonthConstants改成枚举
  6. 去掉serialVersionUID变量,自动控制序列号
  7. 去掉多余的、误导的注释
  8. EARLIEST_DATE_ORDINAL 和 LATEST_DATE_ORDINAL移到SpreadSheeDate中
  9. 基类不宜了解其派生类的情况,使用抽象工厂模式创建一个DayDateFactory。该工厂将创建我们所需要的DayDate的实体,并回答有关实现的问题,例如最大和最小日期之类。
  10. 删除未使用代码
  11. 数组应该移到靠近其使用位置的地方
  12. 将以整数形式传递改为符号传递
  13. 删除默认构造器
  14. 删除final
  15. 使用枚举整理for循环,并使用||连接for中的if语句
  16. 重命名、简化、重构函数
  17. 使用解释临时变量模式来简化函数、将静态方法转变成实例方法、并删除重复实例方法
  18. 算法本身也该有一小部分依赖于实现,将算法上移到抽象类中
最终代码

DayDate.java

/* ====================================================================
* JCommon : a free general purpose class library forthe Java(tm) platform
* =====================================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited aand Contributors
...
* /
package org.jfree.date;

import java.io.Serializable;
import java.util.*;

/**
 * An abstract class that represents immutable dates with a precision of
 * one day. The implementation will map each date to an integer that
 * represents an ordinal number of days from some fixed origin.
 *
 * Why not just use java.util.Date? We will, when it makes sense. At times,
 * java.util.Date can be *too* precise - it represents an instant in time,
 * accurate to 1/1000th of a second (with the date itself depending on the
 * time-zone). Sometimes we just want to represent a particular day (e.g. 21
 * January 2015) without concerning ourselves about the time of day, or the
 * time-zone, or anything else. That's what we've defined DayDate for.
 *
 * Use DayDateFactory.makeDate to create an instance.
 *
 * @author David Gilbert
 * @author Robert C. Martin did a lot of refactoring.
 */
public abstract class DayDate implements Comparable, Serializable {
    public abstract int getOrdinalDay();
    public abstract int getYear();
    public abstract Month getMonth();
    public abstract int getDayOfMonth();

    protected abstract Day getDayOfWeekForOrdinalZero();

    public DayDate plusDays(int days) {
        return DayDateFactory.makeDate(getOrdinalDay() + days);
    }

    public DayDate plusMonths(int months) {
        int thisMonthAsOrdinal = getMonth().toInt() - Month.JANUARY.toInt();
        int thisMonthAndYearAsOrdinal = 12 * getYear() + thisMonthAsOrdinal;
        int resultMonthAndYearAsOrdinal = thisMonthAndYearAsOrdinal + months;
        int resultYear = resultMonthAndYearAsOrdinal / 12;
        int resultMonthAsOrdinal = resultMonthAndYearAsOrdinal % 12 + Month.JANUARY.toInt();
        Month resultMonth = Month.fromInt(resultMonthAsOrdinal);
        int resultDay = correctLastDayOfMonth(getDayOfMonth(), resultMonth, resultYear);
        return DayDateFactory.makeDate(resultDay, resultMonth, resultYear);
    }

    public DayDate plusYears(int years) {
        int resultYear = getYear() + years;
        int resultDay = correctLastDayOfMonth(getDayOfMonth(), getMonth(), resultYear);
        return DayDateFactory.makeDate(resultDay, getMonth(), resultYear);
    }

    private int correctLastDayOfMonth(int day, Month month, int year) {
        int lastDayOfMonth = DateUtil.lastDayOfMonth(month, year);
        if (day > lastDayOfMonth)
            day = lastDayOfMonth;
        return day;
    }

public DayDate getPreviousDayofWeek (Day targetDayofweeek){
int offsetToTarget = targetDayOfWeek.toInt() - getDayfWeek().toInt();
if(offsetToTarget>=0)
offsetToTarget = 7;
return plusDays (offsetToTarget);
}

public DayDate get FollowingDayofWeek (Day targetDayofWeek){
int offsetToTarget = targetDayOfWeek.toInt() - getDayofweek().toInt();
if(offsetToTarget<= 0)
offsetToTarget += 7;
return plusDays (offsetToTarget);
}

public DayDate getNearestDayofWeek (Day targetDayofWeek) {
int offsetToThisWeeksTarget = targetDayOfWeek.toInt()- getDayOfWeek().toInt();
int offsetToFutureTarget = (offsetToThisWeeksTarget +7)&7;
int offsetToPreviousTarget = offsetToFutureTarget - 7

if(offsetToFutureTarget>3)
return plusDays(offsetToPreviousTarget);
else
return plusDays (offsetToFutureTarget);
}

public DayDate getEndOfMonth(){
Month month=getMonth();
intyear=getYear();
int lastDay = DateUtil.lastDayOfMonth (month,year);
return DayDateFactory.makeDate(lastDay,month,year);
}

public Date toDate(){
final Calendar calendar = Calendar.getInstance(); 
int ordinalMonth = getMonth().toInt() - Month.JANUARY.toInt ();
calendar.set (getYear(), ordinalMonth, getDayOfMonth(),0,0,0);
return calendar.getTime();
}

public String toString(){
return String.format("802d-is-8d", getDayofMonth(),getMonth(),getYear());
}

publicDaygetDayOfWeek(){
Day startingDay = getDayOfWeekForordinalzero();
int startingoffset = startingDay.toint() - Day.SUNDAY.toInt();
int ordinalofDayOfWeek = (getordinalDay() + startingoffset)7;
return Day.fromint(ordinalofDayOfWeek + Day.SUNDAY.toint());
}

public int daysSince(DayDate date){
returngetordinalDay() - date.getordinalDay();
}

public boolean ison(DayDate other){
return getordinalDay() = other.getordinalDay();
}

public boolean isBefore(DayDate other){
return getordinalDay()<other.getordinalDay();
}

public boolean isonorBefore(DayDate other){
return getordinalDay()<= other.getordinalDay();
}

public boolean isAfter(DayDate other){
return getordinalDay() > other.getordinalDay();
}

public boolean isonorAfter(DayDate other){
return getordinalDay() >= other.getordinalDay();
}

public boolean isInRange(DayDate d1,DayDated2){
return isInRange(dl,d2,DateInterval.CLOSED);
}

public boolean isInRange (DayDate dl, DayDate d2, DateInterval interval){
int left = Math.min(dl.getordinalDay(),d2.getordina1Day())
int right = Math.max(dl.getOrdinalDay(), d2.getordinalDay());
return interval.isIn(getOrdinalDay(),left,right);
}
}

Month.java

package org.jfree.date;

import java.text.DateFormatSymbols;

public enum Month{
JANUARY(1), FEBRUARY(2), MARCH(3),
APRIL(4), MAY(5), JUNE (6),
JULY(7), AUGUST(8), SEPTEMBER(9),
OCTOBER(10), NOVEMBER(11), DECEMBER(12);
private static DateFormatSymbols dateFormatSymbols = netDateFormatSymbols();
private static final int[] LAST_DAY_OF_MONTH = {0,31,28,31,30,31,30,31,31,31,30,31,30,31,30,31};

private int index;

Month(int index){
this.index=index;
}

public static Month fromInt(int monthIndex) {
for(Monthm:Month.values())(
if(m.index==monthIndex)
return m;
}
throw new IllegalArgumentException("Invalid month :index " + monthIndex)
}

public int lastDay(){
return LAST_DAY_OF_MONTH[index];
}

public int quarter(){
return1+(index-1)/3;
}

public String toString()(
return dateFormatSymbols.getMonths()[index - 1];
}

public String toshortString(){
return date FormatSymbols.getShortMonths()[index -1];
}

public static Month parse(String s) {
s = s.trim();
for(Monthm:Month.values())
if(m.matches(s))
return m;

try{
return fromInt(Integer.parseInt(s));
}
catch (NumberFormatException e){}
throw new IllegalArgumentException("Invalid month"+s);
}

private boolean matches (String s){
return s.equalsIgnoreCase(toString()) || s.equalsIgnoreCase(toShortString());
}

public int toInt(){
return index;
}
}

原文地址:https://blog.csdn.net/renxi0/article/details/140272861

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!