Calendar简单使用
Calendar是jdk提供的日历类。
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();
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使用了工厂模式,根据不同的情况生产不同的对象,那么这些对象是怎么被生产出来的呢。
答案就是:建造者模式
建造者模式,这里将建造者的类为原始类的内部类 使用建造者模式来设置很多的参数,根据对应的参数来建造不同的对象
**
代码:
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,只是一种思想。多种设计模式也可以混用在一起。
值得思考的是为什么要有设计模式,为什么要这么设计,这么设计可以解决什么问题。而不是工厂模式是什么样,建造者模式是什么样。照着抄的话就过于死板。