🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## Java专题二十:设计模式 [TOC] ### 20.1. 创建型模式 #### 20.1.1. 单例模式(Singleton Pattern) > 确保一个对象只有一个实例对象,并且提供了一个全局访问方法该对象的方法 - 延迟创建实例对象,但`getInstance`方法在多线程中可能会创建2个实例对象,当2个线程执行到`uniqueInstance == null`语句判断`uniqueInstance`是空的,然后都创建了该对象,造成了创建2个实例对象的问题 ~~~ public class Singleton { private static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } } ~~~ - 延迟创建实例对象,且使用同步`synchronized`对方法加锁实现同步,但直接对`getInstance`方法加锁的成本太高,因此有了下面的早期创建实例对象和double-checking锁方法创建实例对象 ~~~ public class Singleton { private static Singleton uniqueInstance; private Singleton() {} public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } } ~~~ - 早期创建实例对象,不需要使用同步方法 ~~~ public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return uniqueInstance; } } ~~~ - double-checking锁方法创建实例对象 ~~~ public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } } ~~~ 示例:`java.lang.Runtime`就是使用的早期创建实例对象的方法实现单例模式 ~~~ public class Runtime { private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime; } private Runtime() {} } ~~~ #### 20.1.2. 建造者模式(Builder Pattern) > 用于构建成一个复杂的对象,将构建与表示分离 示例:`java.lang.StringBuffer`和`java.lang.StringBuilder` ~~~ public final class StringBuilder { public StringBuilder append(String str) { super.append(str); return this; } } ~~~ #### 20.1.3. 原型模式(Prototype Pattern) > 用于创建对象的复制本,一般通过实现接口`Cloneable`,并重写`clone`方法 示例:参考 [Java专题十九:浅拷贝与深拷贝](Java专题十九:浅拷贝与深拷贝.md) #### 20.1.4. 工厂模式(Factory Pattern) > 用于创建多个实例对象 示例:`java.util.concurrent.ThreadFactory`用来创建新的线程 ### 20.2. 结构型模式 #### 20.2.1. 装饰器模式(Decorator Pattern) > 在不改变现有类的前提下,为现有类添加新的功能 示例:在IO包中,`InputStream`相当于现有类,`FileterInputStream`相当于抽象装饰类,`BufferedInputStream`、`DataInputStream`为具体实现装饰类,这些具体实现装饰类在`InputStream`的基础增加了新功能 #### 20.2.2. 适配器模式(Adapter Pattern) > 作为2个不兼容接口的桥梁,使他们可以进行相互转换 示例:`java.io.InputStreamReader`就是一个桥梁,将字节流对象转换成字符流对象,`InputStreamReader(InputStream in)` #### 20.2.3. 代理模式(Proxy Pattern) > 在不修改委托类代码的情况下,可以为委托类的方法增加一些操作,如方法中实际代码前后增加日志输出 示例:参考 [Java专题九(2):动态代理](Java专题九(2):动态代理.md) ### 20.3. 行为型模式 #### 20.3.1. 观察者模式(Observer Pattern) > 对象之间存在1对多关系,当被观察对象发生变化时,会通知所有观察者 JDK中自带观察者设计,`java.util.Observable`和`java.util.Observer`,`Observable`是一个类,代表被观察对象,`Observer`是一个接口,代表观察者;使用时被观察对象继承`Observable`类,在发生改变时,主动调用`void setChanged()`说明被观察对象发生改变,然后调用`void notifyObservers(Object arg) `通知观察者变化的内容 示例:现在我们有一个博主类`Blogger`,和一个粉丝类`Fans`,一个博主有很多个粉丝,当博主发表新的文章时,自动通知粉丝 - 被观察者: ~~~ import java.text.SimpleDateFormat; import java.util.*; public class Blogger extends Observable { String name; public Blogger(String name){ this.name = name; } public void publish(String message){ this.setChanged(); Map<String,String> map = new HashMap<String, String>(); map.put("name", name); map.put("message", message); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String nowTime = df.format(System.currentTimeMillis()); map.put("date", nowTime); this.notifyObservers(map); } } ~~~ - 观察者 ~~~ import java.util.HashMap; import java.util.Map; import java.util.Observable; import java.util.Observer; public class Fans implements Observer{ String name; public Fans(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { Map<String,String> map = (HashMap)arg; System.out.println(name+ "=>observe:"+map); } } ~~~ - 验证代码 ~~~ Blogger blogger = new Blogger("ibu"); Fans fan0 = new Fans("fan0"); Fans fan1 = new Fans("fan1"); blogger.addObserver(fan0); blogger.addObserver(fan1); blogger.publish("Java设计模式"); ~~~ 名为`ibu`的博主发布了一篇名为`Java设计模式`,它的2个粉丝,`fan0`和`fan1`都观察到了这个变化。 ~~~ fan1=>observe:{date=2019-12-03 20:55:25, name=ibu, message=Java设计模式} fan0=>observe:{date=2019-12-03 20:55:25, name=ibu, message=Java设计模式} ~~~ #### 20.3.2. 解释器模式(Interpreter Pattern) > 定义了一个语言的语法,然后可以解析 示例:`java.util.regex.Pattern`定义了正则表达式的语法,详细可参考正则 [Java专题七:正则表达式](Java专题七:正则表达式.md)