设计模式:设计模式概述&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;
    }

}
View Code

         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("。。。。。。。。。。。。。。。。。。。。。。。");
    }
}
View Code
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("。。。。。。。。。。。。。。。。。。。。。。。");
    }
    
}
View Code

         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;
    }
}
View Code

    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);
            }
        });

 

posted @ 2018-09-27 16:28  心昂  阅读(215)  评论(0编辑  收藏  举报