Calendar是jdk提供的日历类。
public class Main { public static void main(String[] args) { Calendar calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); // 取月份要加1 int month = calendar.get(Calendar.MONTH) + 1; int day = calendar.get(Calendar.DAY_OF_MONTH); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int seconds = calendar.get(Calendar.SECOND); // 1-7分别代表 -- 星期日,星期一,星期二,星期三,星期四,星期五,星期六 int week = calendar.get(calendar.DAY_OF_WEEK); // 年-月-日 System.out.println("year = " + year); System.out.println("month = " + month); System.out.println("day = " + day); //时-分-秒 System.out.println("hour = " + hour); System.out.println("minute = " + minute); System.out.println("seconds = " + seconds); // 星期 System.out.println("week = " + week); } }
Calendar instance = Calendar.getInstance(); int year = instance.get(Calendar.YEAR); int minute = instance.get(Calendar.MINUTE); System.out.println("当前年份-->"+year); System.out.println("当前分钟-->"+minute);
工厂模式
Calendar instance = Calendar.getInstance();
根据zone 和 locale 创建一个Calendar子对象,但是具体的实现细节和创建了哪个子对象调用者无需关心,完全封装在了工厂的方法中
private static Calendar createCalendar(TimeZone zone, Locale aLocale) { CalendarProvider provider = LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale) .getCalendarProvider(); if (provider != null) { try { return provider.getInstance(zone, aLocale); } catch (IllegalArgumentException iae) { // fall back to the default instantiation } } Calendar cal = null; if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); if (caltype != null) { switch (caltype) { // 根据情况不同来工厂决定创建不同的对象 case "buddhist": cal = new BuddhistCalendar(zone, aLocale); break; case "japanese": cal = new JapaneseImperialCalendar(zone, aLocale); break; case "gregory": cal = new GregorianCalendar(zone, aLocale); break; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }
从 Calendar calendar = Calendar.getInstance();
的 getInstance()
方法进去:
建造者
从以上分析,Calendar使用了工厂模式,根据不同的情况生产不同的对象,那么这些对象是怎么被生产出来的呢。 答案就是:建造者模式 建造者模式,这里将建造者的类为原始类的内部类 使用建造者模式来设置很多的参数,根据对应的参数来建造不同的对象
public static class Builder { private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR private static final int WEEK_YEAR = FIELD_COUNT; private long instant; // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined private int[] fields; // Pseudo timestamp starting from MINIMUM_USER_STAMP. // (COMPUTED is used to indicate that the instant has been set.) private int nextStamp; // maxFieldIndex keeps the max index of fields which have been set. // (WEEK_YEAR is never included.) private int maxFieldIndex; private String type; private TimeZone zone; private boolean lenient = true; private Locale locale; private int firstDayOfWeek, minimalDaysInFirstWeek; public Builder() { } public Builder setInstant(long instant) { if (fields != null) { throw new IllegalStateException(); } this.instant = instant; nextStamp = COMPUTED; return this; //返回自身,链式调用 } public Builder setInstant(Date instant) { return setInstant(instant.getTime()); // NPE if instant == null }
这里只贴出了部分set方法,下面还有很多的set方法就不展示了。
public Calendar build() { if (locale == null) { locale = Locale.getDefault(); } if (zone == null) { zone = TimeZone.getDefault(); } Calendar cal; if (type == null) { type = locale.getUnicodeLocaleType("ca"); } if (type == null) { if (locale.getCountry() == "TH" && locale.getLanguage() == "th") { type = "buddhist"; } else { type = "gregory"; } } switch (type) { case "gregory": cal = new GregorianCalendar(zone, locale, true); break; case "iso8601": GregorianCalendar gcal = new GregorianCalendar(zone, locale, true); // make gcal a proleptic Gregorian gcal.setGregorianChange(new Date(Long.MIN_VALUE)); // and week definition to be compatible with ISO 8601 setWeekDefinition(MONDAY, 4); cal = gcal; break; case "buddhist": cal = new BuddhistCalendar(zone, locale); cal.clear(); break; case "japanese": cal = new JapaneseImperialCalendar(zone, locale, true); break; default: throw new IllegalArgumentException("unknown calendar type: " + type); }
很清晰:使用了建造者,根据不同的属性来构造一个复杂的对象。
why
为什么既然使用了工厂模式来创建对象,那么又进一步的使用建造者模式呢? 我觉得两者并不冲突,工厂模式可以选择创建什么对象,建造者模式可以进一步选择创建对象的属性。 一个经典的例子:去餐厅吃饭,根据口味选择了干锅,但是对于干锅来说也可以选择哪些配菜。 对于Calendar 而言,根据不同的type来创建了不同的Calendar子类。根据Set方法来定制化参数。
反思
对于设计模式而言,并不是一味的死板。并不是设计模式的模型是一层不变的, 工厂模式就一定要Factory,只是一种思想。多种设计模式也可以混用在一起。
值得思考的是为什么要有设计模式,为什么要这么设计,这么设计可以解决什么问题。而不是工厂模式是什么样,建造者模式是什么样。照着抄的话就过于死板。