auto commit

This commit is contained in:
CyC2018 2018-06-04 11:48:12 +08:00
parent ef76419747
commit 95cfcc2a08
4 changed files with 451 additions and 430 deletions

View File

@ -31,7 +31,6 @@
整理自《鸟哥的 Linux 私房菜》 整理自《鸟哥的 Linux 私房菜》
## 网络 :cloud: ## 网络 :cloud:
> [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md) > [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md)
@ -46,7 +45,6 @@
整理自《Unix 网络编程》 整理自《Unix 网络编程》
## 面向对象 :couple: ## 面向对象 :couple:
> [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md) > [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md)
@ -101,10 +99,6 @@ Leetcode 上数据库题目的解题记录。
File, InputStream OutputStream, Reader Writer, Serializable, Socket, NIO File, InputStream OutputStream, Reader Writer, Serializable, Socket, NIO
> [JDK 中的设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/JDK%20中的设计模式.md)
对每种设计模式做了一个总结,并给出在 JDK 中的使用实例。
## 分布式 :sweat_drops: ## 分布式 :sweat_drops:
> [分布式基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式基础.md) > [分布式基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式基础.md)
@ -115,7 +109,6 @@ File, InputStream OutputStream, Reader Writer, Serializable, Socket, NIO
分布式事务、负载均衡算法与实现、分布式锁、分布式 Session、分库分表的分布式困境与应对之策。 分布式事务、负载均衡算法与实现、分布式锁、分布式 Session、分库分表的分布式困境与应对之策。
## 工具 :hammer: ## 工具 :hammer:
> [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md) > [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md)

View File

@ -1,283 +0,0 @@
<!-- GFM-TOC -->
* [一、创建型](#一创建型)
* [1. 单例模式](#1-单例模式)
* [2. 简单工厂模式](#2-简单工厂模式)
* [3. 工厂方法模式](#3-工厂方法模式)
* [4. 抽象工厂](#4-抽象工厂)
* [5. 生成器模式](#5-生成器模式)
* [6. 原型模式](#6-原型模式)
* [二、行为型](#二行为型)
* [1. 责任链](#1-责任链)
* [2. 命令模式](#2-命令模式)
* [3. 解释器模式](#3-解释器模式)
* [4. 迭代器](#4-迭代器)
* [5. 中间人模式](#5-中间人模式)
* [6. 备忘录模式](#6-备忘录模式)
* [7. 观察者模式](#7-观察者模式)
* [8. 策略模式](#8-策略模式)
* [9. 模板方法](#9-模板方法)
* [10. 访问者模式](#10-访问者模式)
* [11. 空对象模式](#11-空对象模式)
* [三、结构型](#三结构型)
* [1. 适配器](#1-适配器)
* [2. 桥接模式](#2-桥接模式)
* [3. 组合模式](#3-组合模式)
* [4. 装饰者模式](#4-装饰者模式)
* [5. 蝇量模式](#5-蝇量模式)
* [6. 动态代理](#6-动态代理)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 一、创建型
## 1. 单例模式
确保只实例化一个对象,并提供一个对象的全局访问点。
```java
java.lang.Runtime#getRuntime()
java.awt.Toolkit#getDefaultToolkit()
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
java.awt.Desktop#getDesktop()
```
## 2. 简单工厂模式
在不对用户暴露对象内部逻辑的前提下创建对象。
## 3. 工厂方法模式
定义创建对象的接口,但是让子类来决定应该使用哪个类来创建。
```java
java.lang.Proxy#newProxyInstance()
java.lang.Object#toString()
java.lang.Class#newInstance()
java.lang.reflect.Array#newInstance()
java.lang.reflect.Constructor#newInstance()
java.lang.Boolean#valueOf(String)
java.lang.Class#forName()
```
## 4. 抽象工厂
提供一个创建相关对象家族的接口,而没有明确指明它们的类。
```java
java.util.Calendar#getInstance()
java.util.Arrays#asList()
java.util.ResourceBundle#getBundle()
java.sql.DriverManager#getConnection()
java.sql.Connection#createStatement()
java.sql.Statement#executeQuery()
java.text.NumberFormat#getInstance()
javax.xml.transform.TransformerFactory#newInstance()
```
## 5. 生成器模式
定义一个新的类来构造另一个类的实例,以创建一个复杂的对象。
它可以封装一个对象的构造过程,并允许按步骤构造。
```java
java.lang.StringBuilder#append()
java.lang.StringBuffer#append()
java.sql.PreparedStatement
javax.swing.GroupLayout.Group#addComponent()
```
## 6. 原型模式
使用原型实例指定要创建对象的类型;通过复制这个原型来创建新对象。
```java
java.lang.Object#clone()
java.lang.Cloneable
```
# 二、行为型
## 1. 责任链
避免将请求的发送者附加到其接收者,从而使其它对象也可以处理请求;将请求以对象的方式发送到链上直到请求被处理完毕。
```java
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
```
## 2. 命令模式
将命令封装进对象中;允许使用命令对象对客户对象进行参数化;允许将命令对象存放到队列中。
```java
java.lang.Runnable
javax.swing.Action
```
## 3. 解释器模式
为语言创建解释器,通常由语言的语法和语法分析来定义。
```java
java.util.Pattern
java.text.Normalizer
java.text.Format
```
## 4. 迭代器
提供一种一致的访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
```java
java.util.Iterator
java.util.Enumeration
```
## 5. 中间人模式
使用中间人对象来封装对象之间的交互。中间人模式可以降低交互对象之间的耦合程度。
```java
java.util.Timer
java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService#submit()
java.lang.reflect.Method#invoke()
```
## 6. 备忘录模式
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
```java
java.util.Date
java.io.Serializable
```
## 7. 观察者模式
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
```java
java.util.EventListener
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener
```
## 8. 策略模式
定义一系列算法,封装每个算法,并使它们可以互换。策略可以让算法独立于使用它的客户端。
```java
java.util.Comparator#compare()
javax.servlet.http.HttpServlet
javax.servlet.Filter#doFilter()
```
## 9. 模板方法
定义算法框架,并将一些步骤的实现延迟到子类。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
```java
java.util.Collections#sort()
java.io.InputStream#skip()
java.io.InputStream#read()
java.util.AbstractList#indexOf()
```
## 10. 访问者模式
提供便捷的维护方式来操作一组对象。它使你在不改变操作对象的前提下,可以修改或扩展对象的行为。
例如集合,它可以包含不同类型的元素,访问者模式允许在不知道具体元素类型的前提下对集合元素进行一些操作。
```java
javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
```
## 11. 空对象模式
使用什么都不做的空对象来替代 NULL。
# 三、结构型
## 1. 适配器
把一个类接口转换成另一个用户需要的接口。
```java
java.util.Arrays#asList()
javax.swing.JTable(TableModel)
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
```
## 2. 桥接模式
将抽象与实现分离开来,使它们可以独立变化。
```java
AWT (It provides an abstraction layer which maps onto the native OS the windowing support.)
JDBC
```
## 3. 组合模式
将对象组合成树形结构来表示整体-部分层次关系,允许用户以相同的方式处理单独对象和组合对象。
```java
javax.swing.JComponent#add(Component)
java.awt.Container#add(Component)
java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)
```
## 4. 装饰者模式
为对象动态添加功能。
```java
java.io.BufferedInputStream(InputStream)
java.io.DataInputStream(InputStream)
java.io.BufferedOutputStream(OutputStream)
java.util.zip.ZipOutputStream(OutputStream)
java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
```
## 5. 蝇量模式
利用共享的方式来支持大量的对象,这些对象一部分内部状态是相同的,而另一份状态可以变化。
Java 利用缓存来加速大量小对象的访问时间。
```java
java.lang.Integer#valueOf(int)
java.lang.Boolean#valueOf(boolean)
java.lang.Byte#valueOf(byte)
java.lang.Character#valueOf(char)
```
## 6. 动态代理
提供一个占位符来控制对象的访问。
代理可以是一些轻量级的对象,它控制着对重量级对象的访问,只有在真正实例化这些重量级对象时才会去实例化它。
```java
java.lang.reflect.Proxy
RMI
```
# 参考资料
- [The breakdown of design patterns in JDK](http://www.programering.com/a/MTNxAzMwATY.html)
- [Design Patterns](http://www.oodesign.com/)

View File

@ -1,9 +1,31 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
* [一、概述](#一概述) * [一、概述](#一概述)
* [二、单例模式](#二单例模式) * [二、创建型](#二创建型)
* [三、简单工厂](#三简单工厂) * [1. 单例模式](#1-单例模式)
* [四、工厂方法模式](#四工厂方法模式) * [2. 简单工厂](#2-简单工厂)
* [五、抽象工厂模式](#五抽象工厂模式) * [3. 工厂方法模式](#3-工厂方法模式)
* [4. 抽象工厂模式](#4-抽象工厂模式)
* [5. 生成器](#5-生成器)
* [6. 原型模式](#6-原型模式)
* [三、行为型](#三行为型)
* [1. 责任链](#1-责任链)
* [2. 命令模式](#2-命令模式)
* [3. 解释器模式](#3-解释器模式)
* [4. 迭代器](#4-迭代器)
* [5. 中间人模式](#5-中间人模式)
* [6. 备忘录模式](#6-备忘录模式)
* [7. 观察者模式](#7-观察者模式)
* [8. 策略模式](#8-策略模式)
* [9. 模板方法](#9-模板方法)
* [10. 访问者模式](#10-访问者模式)
* [11. 空对象模式](#11-空对象模式)
* [四、结构型](#四结构型)
* [1. 适配器](#1-适配器)
* [2. 桥接模式](#2-桥接模式)
* [3. 组合模式](#3-组合模式)
* [4. 装饰者模式](#4-装饰者模式)
* [5. 蝇量模式](#5-蝇量模式)
* [6. 动态代理](#6-动态代理)
* [参考资料](#参考资料) * [参考资料](#参考资料)
<!-- GFM-TOC --> <!-- GFM-TOC -->
@ -14,13 +36,15 @@
拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。 拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。
# 二、单例模式 # 二、创建型
## 意图 ## 1. 单例模式
确保一个类只有一个实例,并提供了一个全局访问点。 ### 意图
## 类图 确保一个类只有一个实例,并提供该实例的全局访问点。
### 类图
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。 使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。
@ -28,22 +52,9 @@
<div align="center"> <img src="../pics//db54db2f-82b2-4222-8d63-e49a8a7fc966.png"/> </div><br> <div align="center"> <img src="../pics//db54db2f-82b2-4222-8d63-e49a8a7fc966.png"/> </div><br>
## 使用场景 ### 实现
- Logger Classes #### 懒汉式-线程不安全
- Configuration Classes
- Accesing resources in shared mode
- Factories implemented as Singletons
## JDK 的使用
- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
- [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
## 实现
### 懒汉式-线程不安全
以下实现中,私有静态变量 uniqueInstance 被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance从而节约资源。 以下实现中,私有静态变量 uniqueInstance 被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance从而节约资源。
@ -66,7 +77,7 @@ public class Singleton {
} }
``` ```
### 懒汉式-线程安全 #### 懒汉式-线程安全
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了对 uniqueInstance 进行多次实例化的问题。 只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了对 uniqueInstance 进行多次实例化的问题。
@ -81,7 +92,7 @@ public static synchronized Singleton getUniqueInstance() {
} }
``` ```
### 饿汉式-线程安全 #### 饿汉式-线程安全
线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。 线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。
@ -89,11 +100,11 @@ public static synchronized Singleton getUniqueInstance() {
private static Singleton uniqueInstance = new Singleton(); private static Singleton uniqueInstance = new Singleton();
``` ```
### 双重校验锁-线程安全 #### 双重校验锁-线程安全
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。 uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
双重校验锁先判断 uniqueInstance 是否已经被初始化了,如果没有被实例化,那么才对实例化语句进行加锁。 双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
```java ```java
public class Singleton { public class Singleton {
@ -116,7 +127,7 @@ public class Singleton {
} }
``` ```
考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程同时执行 if 语句,那么两个线程就会同时进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton(); 这条语句,只是早晚的问题,也就是说会进行两次实例化,从而产生了两个实例。因此必须使用双重校验锁,也就是需要使用两个 if 判断。 考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程同时执行 if 语句,那么两个线程就会同时进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton(); 这条语句,只是先后的问题,也就是说会进行两次实例化,从而产生了两个实例。因此必须使用双重校验锁,也就是需要使用两个 if 判断。
```java ```java
if (uniqueInstance == null) { if (uniqueInstance == null) {
@ -126,25 +137,69 @@ if (uniqueInstance == null) {
} }
``` ```
uniqueInstance 采用 volatile 关键字修饰也是很有必要的。 uniqueInstance 采用 volatile 关键字修饰也是很有必要的。uniqueInstance = new Singleton(); 这段代码其实是分为三步执行。
uniqueInstance = new Singleton(); 这段代码其实是分为三步执行。 1. 分配内存空间。
2. 初始化对象。
3. 将 uniqueInstance 指向分配的内存地址。
1. 分配内存空间。 但是由于 JVM 具有指令重排的特性,有可能执行顺序变为了 1>3>2这在单线程情况下自然是没有问题。但如果是多线程下有可能获得是一个还没有被初始化的实例以致于程序出错。
2. 初始化对象。
3. 将 uniqueInstance 指向分配的内存地址。
但是由于 JVM 具有指令重排的特性,有可能执行顺序变为了 1>3>2这在单线程情况下自然是没有问题。但如果是多线程就有可能 B 线程获得是一个还没有被初始化的对象以致于程序出错 使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
所以使用 volatile 修饰的目的是禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。 #### 枚举实现
# 三、简单工厂 这是单例模式的最佳实践,它实现简单,并且在复杂的序列化或者反射攻击的时候,能够防止实例化多次。
## 意图 ```java
public enum Singleton {
uniqueInstance;
}
```
在创建一个对象时不向客户暴露内部细节; 考虑以下单例模式的实现,该 Singleton 在每次序列化的时候都会创建一个新的实例,为了保证只创建一个实例,必须声明所有字段都是 transient并且提供一个 readResolve() 方法。
## 类图 ```java
public class Singleton implements Serializable{
private static Singleton uniqueInstance;
private Singleton() {
}
public static synchronized Singleton getUniqueInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
```
如果不使用枚举来实现单例模式,会出现反射攻击,因为通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public然后调用构造函数从而实例化对象。如果要防止这种攻击需要在构造函数中添加防止实例化第二个对象的代码。
从上面的讨论可以看出,解决序列化和反射攻击很麻烦,而枚举实现不会出现这两种问题,所以说枚举实现单例模式是最佳实践。
### 使用场景
- Logger Classes
- Configuration Classes
- Accesing resources in shared mode
- Factories implemented as Singletons
### JDK
- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
- [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
## 2. 简单工厂
### 意图
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
### 类图
简单工厂不是设计模式,更像是一种编程习惯。它把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个子类来实例化。 简单工厂不是设计模式,更像是一种编程习惯。它把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个子类来实例化。
@ -170,7 +225,7 @@ public class Client {
} }
``` ```
## 实现 ### 实现
```java ```java
public interface Product { public interface Product {
@ -214,13 +269,13 @@ public class Client {
} }
``` ```
# 四、工厂方法模式 ## 3. 工厂方法模式
## 意图 ### 意图
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化推迟到子类。 定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化推迟到子类。
## 类图 ### 类图
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。 在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
@ -228,7 +283,7 @@ public class Client {
<div align="center"> <img src="../pics//bf0ff9fc-467e-4a3f-8922-115ba2c55bde.png"/> </div><br> <div align="center"> <img src="../pics//bf0ff9fc-467e-4a3f-8922-115ba2c55bde.png"/> </div><br>
## 实现 ### 实现
```java ```java
public abstract class Factory { public abstract class Factory {
@ -264,25 +319,35 @@ public class ConcreteFactory2 extends Factory {
} }
``` ```
# 五、抽象工厂模式 ### JDK
## 意图 - [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
- [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
- [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
- [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
- [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-)
- [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-)
- [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
## 4. 抽象工厂模式
### 意图
提供一个接口,用于创建 **相关的对象家族** 提供一个接口,用于创建 **相关的对象家族**
## 类图 ### 类图
<div align="center"> <img src="../pics//14cfe8d4-e31b-49e0-ac6a-6f4f7aa06ab6.png"/> </div><br> <div align="center"> <img src="../pics//14cfe8d4-e31b-49e0-ac6a-6f4f7aa06ab6.png"/> </div><br>
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。 抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
抽象工厂模式用到了工厂模式来创建单一对象AbstractFactory 中的 createProductA 和 createProductB 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。 抽象工厂模式用到了工厂模式来创建单一对象AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。
至于创建对象的家族这一概念是在 Client 体现Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象在这里这两个对象就有很大的相关性Client 需要同时创建出这两个对象。 至于创建对象的家族这一概念是在 Client 体现Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象在这里这两个对象就有很大的相关性Client 需要同时创建出这两个对象。
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory而工厂模式使用了继承。 从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory而工厂模式使用了继承。
## 代码实现 ### 代码实现
```java ```java
public class AbstractProductA { public class AbstractProductA {
@ -356,8 +421,252 @@ public class Client {
} }
``` ```
### JDK
- [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
- [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
- [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
## 5. 生成器
### 意图
定义一个新的类来构造另一个类的实例,以创建一个复杂的对象。
它可以封装一个对象的构造过程,并允许按步骤构造。
### JDK
- [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
- [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-)
- [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-)
- [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html)
- [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
## 6. 原型模式
### 意图
使用原型实例指定要创建对象的类型;通过复制这个原型来创建新对象。
### JDK
- [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
# 三、行为型
## 1. 责任链
### 意图
避免将请求的发送者附加到其接收者,从而使其它对象也可以处理请求;将请求以对象的方式发送到链上直到请求被处理完毕。
### JDK
- [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
- [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
- [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
## 2. 命令模式
### 意图
将命令封装进对象中;允许使用命令对象对客户对象进行参数化;允许将命令对象存放到队列中。
### JDK
- [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
- [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
- [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
## 3. 解释器模式
### 意图
为语言创建解释器,通常由语言的语法和语法分析来定义。
### JDK
- [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
- [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html)
- All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html)
- [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html)
## 4. 迭代器
### 意图
提供一种一致的访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
### JDK
- [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html)
- [java.util.Enumeration](http://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html)
## 5. 中间人模式
### 意图
使用中间人对象来封装对象之间的交互。中间人模式可以降低交互对象之间的耦合程度。
### JDK
- All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html)
- [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-)
- submit() and invokeXXX() methods of [java.util.concurrent.ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
- scheduleXXX() methods of [java.util.concurrent.ScheduledExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html)
- [java.lang.reflect.Method#invoke()](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-)
## 6. 备忘录模式
### 意图
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
### JDK
- [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html)
## 7. 观察者模式
### 意图
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
### JDK
- [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)
- [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html)
- [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html)
- [RxJava](https://github.com/ReactiveX/RxJava)
## 8. 策略模式
### 意图
定义一系列算法,封装每个算法,并使它们可以互换。策略可以让算法独立于使用它的客户端。
### JDK
- java.util.Comparator#compare()
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
## 9. 模板方法
### 意图
定义算法框架,并将一些步骤的实现延迟到子类。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
### JDK
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.util.AbstractList#indexOf()
## 10. 访问者模式
### 意图
提供便捷的维护方式来操作一组对象。它使你在不改变操作对象的前提下,可以修改或扩展对象的行为。
例如集合,它可以包含不同类型的元素,访问者模式允许在不知道具体元素类型的前提下对集合元素进行一些操作。
### JDK
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
## 11. 空对象模式
使用什么都不做的空对象来替代 NULL。
# 四、结构型
## 1. 适配器
### 意图
把一个类接口转换成另一个用户需要的接口。
### JDK
- [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
- [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
- [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-)
- [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-)
## 2. 桥接模式
### 意图
将抽象与实现分离开来,使它们可以独立变化。
### JDK
- AWT (It provides an abstraction layer which maps onto the native OS the windowing support.)
- JDBC
## 3. 组合模式
### 意图
将对象组合成树形结构来表示整体-部分层次关系,允许用户以相同的方式处理单独对象和组合对象。
### JDK
- javax.swing.JComponent#add(Component)
- java.awt.Container#add(Component)
- java.util.Map#putAll(Map)
- java.util.List#addAll(Collection)
- java.util.Set#addAll(Collection)
## 4. 装饰者模式
### 意图
为对象动态添加功能。
### JDK
- java.io.BufferedInputStream(InputStream)
- java.io.DataInputStream(InputStream)
- java.io.BufferedOutputStream(OutputStream)
- java.util.zip.ZipOutputStream(OutputStream)
- java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
## 5. 蝇量模式
### 意图
利用共享的方式来支持大量的对象,这些对象一部分内部状态是相同的,而另一份状态可以变化。
### JDK
Java 利用缓存来加速大量小对象的访问时间。
- java.lang.Integer#valueOf(int)
- java.lang.Boolean#valueOf(boolean)
- java.lang.Byte#valueOf(byte)
- java.lang.Character#valueOf(char)
## 6. 动态代理
### 意图
提供一个占位符来控制对象的访问。
代理可以是一些轻量级的对象,它控制着对重量级对象的访问,只有在真正实例化这些重量级对象时才会去实例化它。
### JDK
- java.lang.reflect.Proxy
- RMI
# 参考资料 # 参考资料
- 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007. - 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007.
- [Design Patterns](http://www.oodesign.com/) - [Design Patterns](http://www.oodesign.com/)
- [Design patterns implemented in Java](http://java-design-patterns.com/) - [Design patterns implemented in Java](http://java-design-patterns.com/)
- [The breakdown of design patterns in JDK](http://www.programering.com/a/MTNxAzMwATY.html)

View File

@ -1,11 +1,11 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
* [一、设计原则](#一设计原则) * [一、三大特性](#一三大特性)
* [S.O.L.I.D](#solid)
* [其他常见原则](#其他常见原则)
* [二、三大特性](#二三大特性)
* [封装](#封装) * [封装](#封装)
* [继承](#继承) * [继承](#继承)
* [多态](#多态) * [多态](#多态)
* [二、设计原则](#二设计原则)
* [S.O.L.I.D](#solid)
* [其他常见原则](#其他常见原则)
* [三、类图](#三类图) * [三、类图](#三类图)
* [泛化关系 (Generalization)](#泛化关系-generalization) * [泛化关系 (Generalization)](#泛化关系-generalization)
* [实现关系 (Realization)](#实现关系-realization) * [实现关系 (Realization)](#实现关系-realization)
@ -17,93 +17,7 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
# 一、设计原则 # 一、三大特性
## S.O.L.I.D
| 简写 | 全拼 | 中文翻译 |
| :--: | :--: | :--: |
| SRP | The Single Responsibility Principle | 单一责任原则 |
| OCP | The Open Closed Principle | 开放封闭原则 |
| LSP | The Liskov Substitution Principle | 里氏替换原则 |
| ISP | The Interface Segregation Principle | 接口分离原则 |
| DIP | The Dependency Inversion Principle | 依赖倒置原则 |
### 1. 单一责任原则
> 修改一个类的原因应该只有一个。
换句话说就是让一个类只负责一件事,当这个类需要做过多事情的时候,就需要分解这个类。
如果一个类承担的职责过多,就等于把这些职责耦合在了一起,一个职责的变化可能会削弱这个类完成其它职责的能力。
### 2. 开放封闭原则
> 类应该对扩展开放,对修改关闭。
扩展就是添加新功能的意思,因此该原则要求在添加新功能时不需要修改代码。
符合开闭原则最典型的设计模式是装饰者模式,它可以动态地将责任附加到对象上,而不用去修改类的代码。
### 3. 里氏替换原则
> 子类对象必须能够替换掉所有父类对象。
继承是一种 IS-A 关系,子类需要能够当成父类来使用,并且需要比父类更特殊。
如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度。
### 4. 接口分离原则
> 不应该强迫客户依赖于它们不用的方法。
因此使用多个专门的接口比使用单一的总接口要好。
### 5. 依赖倒置原则
> 高层模块不应该依赖于低层模块,二者都应该依赖于抽象;</br>抽象不应该依赖于细节,细节应该依赖于抽象。
高层模块包含一个应用程序中重要的策略选择和业务模块,如果高层模块依赖于低层模块,那么低层模块的改动就会直接影响到高层模块,从而迫使高层模块也需要改动。
依赖于抽象意味着:
- 任何变量都不应该持有一个指向具体类的指针或者引用;
- 任何类都不应该从具体类派生;
- 任何方法都不应该覆写它的任何基类中的已经实现的方法。
## 其他常见原则
除了上述的经典原则,在实际开发中还有下面这些常见的设计原则。
| 简写 | 全拼 | 中文翻译 |
| :--: | :--: | :--: |
|LOD| The Law of Demeter | 迪米特法则 |
|CRP| The Composite Reuse Principle | 合成复用原则 |
|CCP| The Common Closure Principle | 共同封闭原则 |
|SAP| The Stable Abstractions Principle | 稳定抽象原则 |
|SDP| The Stable Dependencies Principle | 稳定依赖原则 |
### 1. 迪米特法则
迪米特法则又叫作最少知识原则Least Knowledge Principle简写 LKP就是说一个对象应当对其他对象有尽可能少的了解不和陌生人说话。
### 2. 合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的。
### 3. 共同封闭原则
一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
### 4. 稳定抽象原则
最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
### 5. 稳定依赖原则
包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。
# 二、三大特性
## 封装 ## 封装
@ -200,6 +114,94 @@ public class Music {
} }
``` ```
# 二、设计原则
## S.O.L.I.D
| 简写 | 全拼 | 中文翻译 |
| :--: | :--: | :--: |
| SRP | The Single Responsibility Principle | 单一责任原则 |
| OCP | The Open Closed Principle | 开放封闭原则 |
| LSP | The Liskov Substitution Principle | 里氏替换原则 |
| ISP | The Interface Segregation Principle | 接口分离原则 |
| DIP | The Dependency Inversion Principle | 依赖倒置原则 |
### 1. 单一责任原则
> 修改一个类的原因应该只有一个。
换句话说就是让一个类只负责一件事,当这个类需要做过多事情的时候,就需要分解这个类。
如果一个类承担的职责过多,就等于把这些职责耦合在了一起,一个职责的变化可能会削弱这个类完成其它职责的能力。
### 2. 开放封闭原则
> 类应该对扩展开放,对修改关闭。
扩展就是添加新功能的意思,因此该原则要求在添加新功能时不需要修改代码。
符合开闭原则最典型的设计模式是装饰者模式,它可以动态地将责任附加到对象上,而不用去修改类的代码。
### 3. 里氏替换原则
> 子类对象必须能够替换掉所有父类对象。
继承是一种 IS-A 关系,子类需要能够当成父类来使用,并且需要比父类更特殊。
如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度。
### 4. 接口分离原则
> 不应该强迫客户依赖于它们不用的方法。
因此使用多个专门的接口比使用单一的总接口要好。
### 5. 依赖倒置原则
> 高层模块不应该依赖于低层模块,二者都应该依赖于抽象;</br>抽象不应该依赖于细节,细节应该依赖于抽象。
高层模块包含一个应用程序中重要的策略选择和业务模块,如果高层模块依赖于低层模块,那么低层模块的改动就会直接影响到高层模块,从而迫使高层模块也需要改动。
依赖于抽象意味着:
- 任何变量都不应该持有一个指向具体类的指针或者引用;
- 任何类都不应该从具体类派生;
- 任何方法都不应该覆写它的任何基类中的已经实现的方法。
## 其他常见原则
除了上述的经典原则,在实际开发中还有下面这些常见的设计原则。
| 简写 | 全拼 | 中文翻译 |
| :--: | :--: | :--: |
|LOD| The Law of Demeter | 迪米特法则 |
|CRP| The Composite Reuse Principle | 合成复用原则 |
|CCP| The Common Closure Principle | 共同封闭原则 |
|SAP| The Stable Abstractions Principle | 稳定抽象原则 |
|SDP| The Stable Dependencies Principle | 稳定依赖原则 |
### 1. 迪米特法则
迪米特法则又叫作最少知识原则Least Knowledge Principle简写 LKP就是说一个对象应当对其他对象有尽可能少的了解不和陌生人说话。
### 2. 合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的。
### 3. 共同封闭原则
一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
### 4. 稳定抽象原则
最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
### 5. 稳定依赖原则
包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。
# 三、类图 # 三、类图
## 泛化关系 (Generalization) ## 泛化关系 (Generalization)