目錄
一 工廠模式
二 Builder 模式
三 裝飾器模式
四 模板模式
五 單例模式
一 工廠模式
- 工廠類都是以 Factory 作為后綴來命名,
- 工廠類的功能主要就是創建物件,
是不是所有的工廠模式中都以 Factory 作為后綴來命名呢?
不是的,我們以 java.util.Calendar 為例,
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
//...
public static Calendar getInstance(TimeZone zone, Locale aLocale){
return createCalendar(zone, aLocale);
}
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 (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;
}
//...
}
上面代碼中的 getInstance() 方法就是 Calendar 類的工廠方法,該方法可以根據不同 TimeZone 和 Locale 創建不同的 Calendar 子類物件,
為什么 Calendar 類是工廠類,卻不以 Factory 作為后綴來命名呢?
因為 Calendar 不僅僅是一個工廠類,Calendar 類除了創建物件外,還有很多其他的功能,所以沒有用 Factory 作為后綴來命名,是不是感覺實際的應用更靈活,
二 Builder 模式
一般來說,Builder 模式有兩種實作方式:
- 一種是單獨定義一個 Builder 類,
- 一種是將 Builder 實作為原始類的內部類,
我們還是以 Calendar 來說明 Builder 模式的使用:
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
//...
public static class Builder {
private static final int NFIELDS = FIELD_COUNT + 1;
private static final int WEEK_YEAR = FIELD_COUNT;
private long instant;
private int[] fields;
private int nextStamp;
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;
}
//...省略n多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);
}
cal.setLenient(lenient);
if (firstDayOfWeek != 0) {
cal.setFirstDayOfWeek(firstDayOfWeek);
cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
}
if (isInstantSet()) {
cal.setTimeInMillis(instant);
cal.complete();
return cal;
}
if (fields != null) {
boolean weekDate = isSet(WEEK_YEAR) && fields[WEEK_YEAR] > fields[YEAR];
if (weekDate && !cal.isWeekDateSupported()) {
throw new IllegalArgumentException("week date is unsupported by " + type);
}
for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
for (int index = 0; index <= maxFieldIndex; index++) {
if (fields[index] == stamp) {
cal.set(index, fields[NFIELDS + index]);
break;
}
}
}
if (weekDate) {
int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
int dayOfWeek = isSet(DAY_OF_WEEK) ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
}
cal.complete();
}
return cal;
}
}
}
Calendar 類既然已經有了 getInstance() 工廠方法來創建 Calendar 類物件,為什么還要用 Builder 來創建 Calendar 類物件呢?
哈哈,其實 getInstance() 方法使用的是工廠模式,而工廠模式是用來創建不同但是相同型別的物件,
Builder 模式用來創建一種型別的復雜物件,通過設定不同的引數,定制化創建不同的物件,
三 裝飾器模式
裝飾器模式中的裝飾器類是對原始類功能的增強,Java IO 類別庫是裝飾器模式的非常經典的應用,下面以 Collections 類來說明,
Collections 類是集合容器的工具類,有很多靜態方法用來創建各種集合容器,
public class Collections {
private Collections() {}
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
return new UnmodifiableCollection<>(c);
}
static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 1820017752578914078L;
final Collection<? extends E> c;
UnmodifiableCollection(Collection<? extends E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
}
public int size() {return c.size();}
public boolean isEmpty() {return c.isEmpty();}
public boolean contains(Object o) {return c.contains(o);}
public Object[] toArray() {return c.toArray();}
public <T> T[] toArray(T[] a) {return c.toArray(a);}
public String toString() {return c.toString();}
public Iterator<E> iterator() {
return new Iterator<E>() {
private final Iterator<? extends E> i = c.iterator();
public boolean hasNext() {return i.hasNext();}
public E next() {return i.next();}
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
// Use backing collection version
i.forEachRemaining(action);
}
};
}
public boolean add(E e) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
hrow new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> coll) {
return c.containsAll(coll);
}
public boolean addAll(Collection<? extends E> coll) {
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> action) {
c.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
@Override
public Spliterator<E> spliterator() {
return (Spliterator<E>)c.spliterator();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> parallelStream() {
return (Stream<E>)c.parallelStream();
}
}
}
盡管 UnmodifiableCollection 類可以算是對 Collection 類的一種功能增強,但這點還不具備足夠的說服力來斷定 UnmodifiableCollection 就是 Collection 類的裝飾器類,
最關鍵的一點是,UnmodifiableCollection 的建構式接收一個 Collection 類物件,然后對其所有的函式進行了包裹(Wrap):重新實作(比如 add() 函式)或者簡單封裝(比如 stream() 函式),
而簡單的介面實作或者繼承,并不會如此來實作 UnmodifiableCollection 類,所以,從代碼實作的角度來說,UnmodifiableCollection 類是典型的裝飾器類,
四 模板模式
模板模式常用在框架的設計中,提供框架的擴展點,在不對框架進行大的修改的前提下,基于擴展點定制化框架的功能,我們以 Collections 類的 sort() 函式來說明,
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("Zhangsan", 19));
users.add(new User("Lisi", 20));
users.add(new User("Wangwu", 18));
Collections.sort(users, new AgeAscComparator());
print(users);
Collections.sort(users, new NameAscComparator());
print(users);
}
public static void print(List<User> students) {
for (User s : students) {
System.out.println(s.getName() + " " + s.getAge());
}
}
public static class AgeAscComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return u1.getAge() - u2.getAge();
}
}
public static class NameAscComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return u1.getName().compareTo(u2.getName());
}
}
}
為什么說 Collections.sort() 函式用到了模板模式?
Collections.sort() 實作了對集合的排序,為了實作擴展性,將“比較大小”這部分邏輯,委派給用戶來實作,我們可以把比較大小這部分邏輯看做整個排序邏輯的一部分,所以看做是模板模式,
五 單例模式
JDK 中 java.lang.Runtime 類就是一個單例類,每個 Java 應用在運行時會啟動一個 JVM 行程,每個 JVM 行程都只對應一個 Runtime 實體,用于查看 JVM 狀態以及控制 JVM 行為,
行程內唯一,所以比較適合設計為單例,在編程的時候,我們不能自己去實體化一個 Runtime 物件,只能通過 getRuntime() 靜態方法來獲得,
/**
* Every Java application has a single instance of class
* <code>Runtime</code> that allows the application to interface with
* the environment in which the application is running. The current
* runtime can be obtained from the <code>getRuntime</code> method.
* <p>
* An application cannot create its own instance of this class.
*
* @author unascribed
* @see java.lang.Runtime#getRuntime()
* @since JDK1.0
*/
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
//....
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
}
//...
}
從上面代碼我們可以看出,它使用了最簡單的餓漢式的單例實作方式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/261051.html
標籤:java
