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

相关推荐

  1. clean code-代码整洁 阅读笔记

    2024-07-12 19:14:04       17 阅读
  2. clean code-代码整洁 阅读笔记

    2024-07-12 19:14:04       28 阅读
  3. 阅读笔记——《代码整洁》ch2

    2024-07-12 19:14:04       28 阅读
  4. 代码整洁学习笔记

    2024-07-12 19:14:04       21 阅读
  5. 前端代码整洁规范

    2024-07-12 19:14:04       44 阅读
  6. 代码整洁总结

    2024-07-12 19:14:04       38 阅读
  7. Redies

    2024-07-12 19:14:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 19:14:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 19:14:04       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 19:14:04       58 阅读
  4. Python语言-面向对象

    2024-07-12 19:14:04       69 阅读

热门阅读

  1. MySQL慢查询日志(Slow Query Log)

    2024-07-12 19:14:04       17 阅读
  2. ZCC5429 异步升压芯片

    2024-07-12 19:14:04       20 阅读
  3. 介绍一下docker的打包命令

    2024-07-12 19:14:04       22 阅读
  4. 华为OJ平台

    2024-07-12 19:14:04       19 阅读
  5. inline与nullptr

    2024-07-12 19:14:04       21 阅读
  6. ActiViz中的跟随者vtkFollower

    2024-07-12 19:14:04       22 阅读
  7. 常见的load_file()读取的敏感信息

    2024-07-12 19:14:04       21 阅读
  8. tomcat的介绍与优化

    2024-07-12 19:14:04       21 阅读
  9. Elasticsearch实战指南:从下载到高级应用全解析

    2024-07-12 19:14:04       21 阅读
  10. python .join用法

    2024-07-12 19:14:04       18 阅读
  11. 力扣995.K连续位的最小翻转次数

    2024-07-12 19:14:04       22 阅读
  12. ubuntu cp 命令 拷贝文件

    2024-07-12 19:14:04       20 阅读
  13. 探索 Scikit-Learn:机器学习的强大工具库

    2024-07-12 19:14:04       19 阅读
  14. C# —— try catch

    2024-07-12 19:14:04       15 阅读