设计模式:设计模式概述&JDK中的应用
【概述】
设计模式主要分为三大类:创建型、结构型、行为型
【创建型】
目的:对象怎么来的?创建对象时隐藏创建逻辑,不直接使用new。
1.1 单例模式 Singleton:
原理:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
举例:java.lang.Runtime;
Runtime rt = Runtime.getRuntime(); //每一个运行的java都会有唯一的一个运行时实例。运行过程中实例会受影响。 源码:private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime }
1.2 原型模式 Prototype:
原理:用于创建重复的对象,同时又保证性能。实现了一个原型接口,该接口用于创建当前对象的克隆。浅拷贝(Cloneable)和深拷贝(Serializable读取二进制流)
举例:Object.clone(); Spring框架bean装配时scope的类型:Singleton,ProtoType
public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); }
1.3 工厂模式 Factory:
原理:创建对象时不会对客户端暴露创建逻辑,而且是通过使用一个统统的接口来指向新创建的对象。
举例: java.lang.Class
Class clazz = new Object().getClass; Object obj = clazz.newInstance(); // 利用反射创建实例。
1.4 抽象工厂模式 Abstract:
原理:接口是负责创建一个相关对象的工厂,不需要显示指定他们的类。每个生成的工厂都能按照工厂模式提供对象。
举例:java.text.NumberFormat;
NumberFormat numberFormat = NumberFormat.getInstance(Locale.CANADA); 源码: public static NumberFormat getInstance(Locale) { return getInstance(inLocale, NUMBERSTYLE); //返回的抽象数据类型,会进一步判断choice的类别来返回设置的格式。 }
1.5 建造者模式 Builder:
原理:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的标识。顺序无关的对象可以都先创建好。
举例:Java.lang.StringBuilder;
StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(); //通过系统拷贝方法System.arrayCopy()方法生成一个新的字符序列
【结构型】
目的:对象和谁有关?关注类和对象,继承的概念被用来组合接口/对象获得新功能。
2.1 适配器模式 Adapter:
原理:作为两个不兼容的接口之间的桥梁。主要是解决正在服役的项目的问题。
举例:java.util.Arrays.asList(); java.io.InputStreamReader(InputStream)
String[] arr = {"1", "2", "3"}; List<String> arrayList = Arrays.asList(arr); 源码: public static <T> List<T> asList(T.. a) { return new ArrayList<>(a); // 利用数组数据初始化elementData和size字段,这两个值是ArrayList的核心属性。 }
2.2 桥接模式 Bridage:
原理:把抽象化与实现化解耦,使它们都可以独立的变化。
举例:java.sql.Connection/DriverManager;
try { Class.forName("com.mysql.jdbc.Driver"); // 装载进去,即具体的Driver装载到DriverManager中。 String url = ""; String user = ""; String password = ""; Connection con = DriverManager.getConnection(url, user, password); } catch (Exception e) {
...........
}
源码分析:DriverManager就相当于是一个Bridage Driver --> DriverManager(Bridage) --> Connection public class Driver extends NonRegisteringDriver implements java.sql.Driver { static { try { java.sql.DriverManager.registerDriver(new Driver); } catch (SQLException e) { ................ } } }
2.3 过滤器模式 Filter:
原理:使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
举例:java.util.map(JDK8);
Map<Integer, List<Person >> groupMap = persons.stream().collect(Collectors.groupingBy(Person::getGender)); groupMap.forEach((k, v) -> { // k是分组的指标,v是list集合 System.out.println(k); v.forEach(System.out::println); });
2.4 组合模式 Composite:
原理:创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
举例:java.util.Map;
Map<String, String> map1 = new HashMap<String, String>(); Map<String, String> map2 = new HashMap<String, String>(); map1.putAll(m2); // 自己可以装配和自己类型相同的对象组
2.5 装饰器模式 Decorator:
原理:允许动态地向一个现有的对象添加新的功能,同时又不改变其结构。类似extends,但不需要产生大量子类,关键还是动态产生。
举例:java.io.BufferedInputStream(InputStream);
源码分析: public BufferedInputStream(InputStream in, int size) { super(in); // inputStream类型的in对象 if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; //实际操作的是in对象,close结构没变 in = null; if (input != null) input.close(); return; } // Else retry in case a new buf was CASed in fill() } }
2.6 外观模式 Facade:
原理:为复杂的模块获子系统提供外界访问的模块。
举例:javax.servlet.http.HttpServletRequest;
源码分析: public HttpServletRequest getRequest() { if (facade == null) { facade = new RequestFacade(this); // 里边有许多内部组件之间交互的public类型方法,但又不能对外开放。如setComet,setRequestedSessionId等。 } }
2.7 享元模式 Flyweight:
原理:减少创建对象的数量,以减少内存占用和提供性能。尝试重用现有的同类对象,如果未找到匹配的对象,则创建新的对象。
举例:java.lang.Integer;
Integer integer = Integer.valueof(1);
源码: assert IntegerCache.hight >=127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; // 先判断,满足条件就从缓存数据中取,不再创建新对象。 return new Integer(i);
2.8 代理模式 Proxy:
原理:在代理模式中,我们创建具有目标对象的代理对象,以便向外界提供功能接口。
举例:java.lang.reflect.InvocationHnadler;
final ISomeService target = new SomeServiceImpl(); // 自由变量 ISomeService proxy = (ISomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { // 织入:交叉业务逻辑切入到主业务中。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SomeUtils.doTransaction(); Object result = method.invoke(target, args); SomeUtils.doLog(); return result; } }); proxy.doSome(); proxy.doSecond();
【行为型】
目的:对象与对象在干吗?关注对象之间的通信
3.1 责任链模式 Chain of Responsibility:
原理:通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者.
举例:java.util.logging.Logger;
public void log(LogRecord record) { if (record.getLevel().intValue() < levelValue || levelValue == offValue) { return; } Filter theFilter = filter; if (theFilter != null && !theFilter.isLoggable(record)) { return; } // Post the LogRecord to all our Handlers, and then to // our parents' handlers, all the way up the tree. Logger logger = this; while (logger != null) { for (Handler handler : logger.getHandlers()) { handler.publish(record); //获取Handler的引用,交给其处理 } if (!logger.getUseParentHandlers()) { break; } logger = logger.getParent(); } }
3.2 命令模式 Command:
原理: 数据驱动,以Command的形式包裹在对象中,并传给Invoker调用对象。Invoker对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。适用于:行为的记录、撤销、重做、事务等。
举例:java.lang.runnable;
Runnable runable = () -> System.out.println(“具体命令”); // 即Command (run)包裹在runnable对象中。 Thread Thread1 = new Thread(runable); // 将包裹cmd的对象交给Thread,即Invoker Thread1.start(); // Invoker调用 cmd的方法。
3.3 解释器模式 Interpreter:
原理:提供了评估语言的语法或表达式的方法。实现了一个表达式接口,该接口解释了一个待定的上下文。常用于SQL解析、符号处理引擎等。
举例:java.text.Format; java.util.Pattern;
Pattern pattern = Pattern.compile("regexExpression"); // 解释器的作用 Matcher match = pattern.matcher("expresionString"); Boolean result = match.matches(); // Pattern实例是不可变的,并且支持并发和多线程安全,而Matcher不支持,则另一种表达方式 Boolean result = Pattern.matches("regexExpression", "expresionString")
3.4 迭代器模式 Iterator:
原理:顺序访问集合对象的元素,不需要知道集合对象的底层表示。
举例:java.util.Iterator;
private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return int expectedModCount; // For fast-fail int index; // current slot Entry<K,V> current; // current entry HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } final Entry<K,V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); if ((next = e.next) == null) { Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e; return e; }
3.5 中介者模式 Mediator:
原理:提供了一个中介类,该类处理不同类之间的通信。符合迪米特法则(最少知道原则),减少实体之间的相互作用。
举例:java.util.concurrent.Executor; java.util.Timer; java.lang.reflect.Method;
Runnable runable = () -> System.out.println(“具体命令”); // 即Command (run)包裹在runnable对象中。 ExecoturService executorService = Executors.newSingleThreadExecutor(); // 中介类 executorService.execute(runable); // 中介类来执行
3.6 备忘录模式 Memento:
原理:保存一个对象的某个状态,以便在适当的时候恢复对象。
举例:java.io.Serializable
public class DemoBean implements Serializable { private static final long serialVersionUID = 1L; ................ } ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:/demoBean.txt"))); //可以备忘到文件,容器缓存中等 oos.writeObject(demoBean) // 将对象demoBean保留下来 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:/demoBean.txt"))); DemoBean demoBean = (DemoBean)ois.readObject(); // 恢复
3.7 观察者模式 Observer:
原理:当一个对象被修改时,会自动通知它依赖的对象。一般使用异步方式。
举例:java.util.EventListener&java.uti.EventObject; javax.servlet.http.HttpSessionBindingListener
1)事件对象
import java.util.EventObject; public class MyEvent extends EventObject { private static final long serialVersionUID = 1L; private int sourceState; public MyEvent(Object source) { super(source); sourceState = ((Source)source).getFlag(); } public int getSourceState() { return sourceState; } }
2)事件监听器(观察者)
import java.util.EventListener; /** * * @author Thief * */ public class StateChangeListener implements EventListener { public void handleEvent(MyEvent event) { System.out.println("触发状态改变事件。。。"); System.out.println("当前事件源状态为:" + event.getSourceState()); System.out.println("。。。。。。。。。。。。。。。。。。。。。。。"); } }
import java.util.EventListener; /** * * @author Thief * */ public class StateChangeToOneListener implements EventListener { public void handleEvent(MyEvent event) { System.out.println("触发状态变为1的事件。。。"); System.out.println("当前事件源状态为:" + event.getSourceState()); System.out.println("。。。。。。。。。。。。。。。。。。。。。。。"); } }
3)事件源(被观察者)
import java.util.EventListener; import java.util.HashSet; import java.util.Set; /** * * @author Thief * */ public class Source { private int flag = 0; Set<EventListener> listeners = new HashSet<EventListener>(); /** * 注册事件监听器 * * @param listener */ public void addStateChangeListener(StateChangeListener listener) { listeners.add(listener); } /** * 注册事件监听器 * * @param listener */ public void addStateChangeToOneListener(StateChangeToOneListener listener) { listeners.add(listener); } /** * 当事件发生时,通知注册在事件源上的所有事件做出相应的反映 */ public void notifyListener() { for (EventListener listener : listeners) { try { ((StateChangeListener)listener).handleEvent(new MyEvent(this)); } catch (Exception e) { if (flag == 1) { ((StateChangeToOneListener)listener).handleEvent(new MyEvent(this)); } } } } /** * 改变状态 */ public void changeFlag() { flag = (flag == 0 ? 1 : 0); notifyListener(); } public int getFlag() { return flag; } }
3.8 状态模式 State:
原理:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
举例:java.util.Iterator;
3.9 策略模式 Strategy:
原理:策略对象改变context对象的执行算法。
举例:java.util.concurrent.ThreadPoolExecutor; java.util.Comparator;
Runnable runable = () -> System.out.println(“具体命令”); // 即Command (run)包裹在runnable对象中。 ThreadPoolExecutor executorService; executorService = new ThreadPoolExecutor(1,1,1L,TimeUnit.MINUTES,new ArrayBlockingQueue<1>, new ThreadPoolExecutor.AbortPolicy); //丢弃并抛出异常 executorService = new ThreadPoolExecutor(1,1,1L,TimeUnit.MINUTES,new ArrayBlockingQueue<1>, new ThreadPoolExecutor.DiscardPolicy); //丢弃不抛出异常 executorService = new ThreadPoolExecutor(1,1,1L,TimeUnit.MINUTES,new ArrayBlockingQueue<1>, new ThreadPoolExecutor.DiscardOldestPolicy); //丢弃队列最前面的任务,然后重新尝试执行任务。 executorService = new ThreadPoolExecutor(1,1,1L,TimeUnit.MINUTES,new ArrayBlockingQueue<1>, new ThreadPoolExecutor.DiscardPolicy); //由调用线程处理任务
3.10 空对象模式 Null Object:
原理:Null对象不是检查空值,而是反应一个不做任何动作的关系。这样的null对象也可以在数据不可用的时候提供默认的行为。
举例:java.util.Collections.EMPTY_LIST;
源码走读: @SuppressWarnings("unchecked") public static final List EMPTY_LIST = new EmptyList<>();
3.11 模板模式 Template:
原理:主要解决一些方法通用,却在每一个子类都重写了这一方法。将这些通用的方法抽象出来。
举例:java.util.Coolections; org.springframework.jms.core.JmsTemplate;
public static <T extends Comparable<? super T>> void sort(List<T> list) { Object[] a = list.toArray(); Arrays.sort(a); ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) { i.next(); i.set((T)a[j]); } }
3.12 访问者模式 Visitor:
原理:主要将数据结构与数据操作分离,稳定的数据结构和以便的操作耦合问题。
举例:java.nio.file.FileVisitor; // 通过Files.walkFileTree方法实现对文件树中每一个文件的访问。
// 使用FileVisitor对目录进行遍历 Files.walkFileTree(Paths.get("d:", "workspace"), new SimpleFileVisitor<Path>() { // 在访问子目录前触发该方法 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println("正在访问" + dir + "目录"); return FileVisitResult.CONTINUE; } // 在访问文件时触发该方法 @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("正在访问" + file + "文件"); if (file.endsWith("FilesTest.java")) { System.out.println("------已找到FilesTest.java,文件内容-----"); List<String> list = Files.readAllLines(file); // 打印出文件的内容 System.out.println(list); return FileVisitResult.TERMINATE; } return FileVisitResult.CONTINUE; } // 在访问失败时触发该方法 @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { // 写一些具体的业务逻辑 return super.visitFileFailed(file, exc); } // 在访问目录之后触发该方法 @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { // 写一些具体的业务逻辑 return super.postVisitDirectory(dir, exc); } });