工厂模式在Calendar类中的应用
- Calendar类的工厂代码和功能代码在一个类中。
- Calender.getInstance()的方法实现。是一个工厂模式,根据传入的时区和locale决定使用不同的历法。
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; } //... }
建造者模式在Calendar类中的应用
- 关键点在于省略的set方法们。建造者模式和工厂模式都存在于Calendar类中,为啥?因为工厂模式是根据传入的某个参数构造不同的实体类型;而建造者模式是应对复杂的实体初始化,通过不同的set方法构造定制化的实体。还是那句话,两者的目的有所区别。
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; } //... }
装饰器模式在Collections类中的应用
- 关键点在于UnmodifiableCollection的构造函数接收了c参数对于原来的collection进行了包裹并增强;而普通的接口实现是不做这个的。
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(); } } }
适配器模式在Collections类中的应用
- 老版本的 JDK 提供了 Enumeration 类来遍历容器。新版本的 JDK 用 Iterator 类替代 Enumeration 类来遍历容器。为了兼容老的客户端代码(使用老版本 JDK 的代码),保留了 Enumeration 类,并且在 Collections 类中,仍然保留了 enumaration() 静态方法(因为我们一般都是通过这个静态函数来创建一个容器的 Enumeration 类对象)。
- 在新版本的 JDK 中,Enumeration 类是适配器类。它适配的是客户端代码(使用 Enumeration 类)和新版本 JDK 中新的迭代器 Iterator 类。
/** * Returns an enumeration over the specified collection. This provides * interoperability with legacy APIs that require an enumeration * as input. * * @param <T> the class of the objects in the collection * @param c the collection for which an enumeration is to be returned. * @return an enumeration over the specified collection. * @see Enumeration */ public static <T> Enumeration<T> enumeration(final Collection<T> c) { return new Enumeration<T>() { private final Iterator<T> i = c.iterator(); public boolean hasMoreElements() { return i.hasNext(); } public T nextElement() { return i.next(); } }; }
模板模式在Collections中的应用
- Collections.sort() 就用到了模板模式,他讲比较大小的实现委派给用户实现。sort是整个排序过程中的一步。
- 通过类似回调的机制进行。
`public class Demo { public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add(new Student("Alice", 19, 89.0f)); students.add(new Student("Peter", 20, 78.0f)); students.add(new Student("Leo", 18, 99.0f)); Collections.sort(students, new AgeAscComparator()); print(students); Collections.sort(students, new NameAscComparator()); print(students); Collections.sort(students, new ScoreDescComparator()); print(students); } public static void print(List<Student> students) { for (Student s : students) { System.out.println(s.getName() + " " + s.getAge() + " " + s.getScore()); } } public static class AgeAscComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } } public static class NameAscComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); } } public static class ScoreDescComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { if (Math.abs(o1.getScore() - o2.getScore()) < 0.001) { return 0; } else if (o1.getScore() < o2.getScore()) { return 1; } else { return -1; } } } }
观察者模式在JDK的应用
- Changed 用来表示observable更新了。
- 所以当调用notifyOverservers,需要先调用setChanged,就不会给其他的观察者通知。
- changed成员变量还是必须的,这么做的好处是可以将“跟踪变化”和“通知观察者”两步分开,处理一些复杂的逻辑,
- Observable为了保证线程安全,他的方法在调用时都会加锁,除了notifyOverservers。 这个方法是为了性能问题,用一个本地的数组快照去保存当时的观察者然后去一个个通知。
- 每个观察者的update方法不可知,可能造成线程等待时间过长。
- 而Vector是线程不安全的
- 拷贝出来的观察者数组(本地变量)是一个线程私有的。
- 可能存在新加的无法被通知,新删除的依然被通知。
public interface Observer { void update(Observable o, Object arg); } public class Observable { private boolean changed = false; private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } }
单例模式在Runtime类中的应用
- 每个Java应用运行时都是一个进程(唯一),所以只对应一个Runtime运行实例。用来查看JVM状态和控制JVM行为。
- 这个类是一个单例类,实例只能通过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); } //... }
其他设计模式应用汇总
-
在讲到模板模式的时候,我们结合 Java Servlet、JUnit TestCase、Java InputStream、Java AbstractList 四个例子,来具体讲解了它的两个作用:扩展性和复用性。
-
在讲到享元模式的时候,我们讲到 Integer 类中的 -128~127 之间的整型对象是可以复用的,还讲到 String 类型中的常量字符串也是可以复用的。这些都是享元模式的经典应用。
- 在讲到职责链模式的时候,我们讲到Java Servlet 中的 Filter 就是通过职责链来实现的,同时还对比了 Spring 中的 interceptor。实际上,拦截器、过滤器这些功能绝大部分都是采用职责链模式来实现的。
- 在讲到的迭代器模式的时候,我们重点剖析了 Java 中 Iterator 迭代器的实现,手把手带你实现了一个针对线性数据结构的迭代器。