@ -79,9 +79,9 @@ URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基
|
|||||||
|
|
||||||
## POST:传输实体主体
|
## POST:传输实体主体
|
||||||
|
|
||||||
POST 主要目的不是获取资源,而是传输实体主体数据。
|
POST 主要目的不是获取资源,而是传输存储在内容实体中的数据。
|
||||||
|
|
||||||
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体部分。
|
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在内容实体。
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
|
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
|
||||||
|
@ -161,7 +161,7 @@ public boolean Find(int target, int [][] array) {
|
|||||||
|
|
||||||
**题目要求**
|
**题目要求**
|
||||||
|
|
||||||
以 O(1) 的空间复杂度和 O(n) 的空间复杂度来求解。
|
以 O(1) 的空间复杂度和 O(n) 的时间复杂度来求解。
|
||||||
|
|
||||||
**解题思路**
|
**解题思路**
|
||||||
|
|
||||||
@ -195,27 +195,11 @@ public String replaceSpace(StringBuffer str) {
|
|||||||
|
|
||||||
**题目描述**
|
**题目描述**
|
||||||
|
|
||||||
输入一个链表的头结点,从尾到头反过来打印出每个结点的值。
|
输入链表的第一个节点,从尾到头反过来打印出每个结点的值。
|
||||||
|
|
||||||
**解题思路**
|
**解题思路**
|
||||||
|
|
||||||
典型的"后进先出",可使用栈或者递归。
|
栈
|
||||||
|
|
||||||
正向遍历然后调用 Collections.reverse()。
|
|
||||||
|
|
||||||
```java
|
|
||||||
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
|
||||||
ArrayList<Integer> ret = new ArrayList<>();
|
|
||||||
while (listNode != null) {
|
|
||||||
ret.add(listNode.val);
|
|
||||||
listNode = listNode.next;
|
|
||||||
}
|
|
||||||
Collections.reverse(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
使用 Stack
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
@ -245,7 +229,23 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
不使用库函数,并且不使用递归的迭代实现,利用链表的头插法为逆序的特性。
|
正向遍历然后调用 Collections.reverse()。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
|
ArrayList<Integer> ret = new ArrayList<>();
|
||||||
|
while (listNode != null) {
|
||||||
|
ret.add(listNode.val);
|
||||||
|
listNode = listNode.next;
|
||||||
|
}
|
||||||
|
Collections.reverse(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
不使用库函数,并且不使用递归。利用链表头插法为逆序的特点。
|
||||||
|
|
||||||
|
头结点和第一个节点的区别:头结点是在头插法中使用的一个额外节点,这个节点不存储值;第一个节点就是链表的第一个真正存储值的节点。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
@ -605,6 +605,19 @@ public int NumberOf1(int n) {
|
|||||||
|
|
||||||
## 16. 数值的整数次方
|
## 16. 数值的整数次方
|
||||||
|
|
||||||
|
**题目描述**
|
||||||
|
|
||||||
|
给定一个 double 类型的浮点数 base 和 int 类型的整数 exponent。求 base 的 exponent 次方。
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
下面的讨论中 x 代表 base,N 代表 exponent。
|
||||||
|
|
||||||
|
- 当 x 为偶数时,x<sup>N</sup> = (x \* x)<sup>N / 2</sup>;
|
||||||
|
- 当 x 为奇数时,x<sup>N</sup> = x \* (x \* x)<sup>N / 2</sup>;
|
||||||
|
|
||||||
|
因为 (x \* x)<sup>N / 2</sup> 可以通过递归求解,并且每递归一次,N 都减小一半,因此整个算法的时间复杂度为 logN。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public double Power(double base, int exponent) {
|
public double Power(double base, int exponent) {
|
||||||
if (exponent == 0) return 1;
|
if (exponent == 0) return 1;
|
||||||
@ -662,6 +675,19 @@ private void printNumber(char[] number) {
|
|||||||
|
|
||||||
## 18.1 在 O(1) 时间内删除链表节点
|
## 18.1 在 O(1) 时间内删除链表节点
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
- 如果链表不是尾节点,那么可以直接将下一个节点的值赋给节点,令节点指向下下个节点,然后删除下一个节点,时间复杂度为 O(1)。
|
||||||
|
|
||||||
|
<div align="center"> <img src="../pics//72f9bc11-06a9-40b4-8939-14f72e5cb4c3.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
|
- 否则,就需要先遍历链表,找到节点的前一个节点,然后让前一个节点指向节点的下一个节点,时间复杂度为 O(N)。
|
||||||
|
|
||||||
|
<div align="center"> <img src="../pics//2a398239-ee47-4ea1-b2d8-0ced638839ef.png"/> </div><br>
|
||||||
|
|
||||||
|
- 综上,如果进行 N 次操作,那么大约需要移动节点的次数为 N-1+N=2N-1,其中 N-1 表示不是链表尾节点情况下的移动次数,N 表示是尾节点情况下的移动次数。(2N-1)/N \~ 2,因此该算法的时间复杂度为 O(1)。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
|
public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
|
||||||
if (head == null || head.next == null || tobeDelete == null) return null;
|
if (head == null || head.next == null || tobeDelete == null) return null;
|
||||||
@ -681,6 +707,17 @@ public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
|
|||||||
|
|
||||||
## 18.2 删除链表中重复的结点
|
## 18.2 删除链表中重复的结点
|
||||||
|
|
||||||
|
**题目描述**
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input : 1->2->3->3->4->4->5
|
||||||
|
Output : 1->2->5
|
||||||
|
```
|
||||||
|
|
||||||
|
**解题描述**
|
||||||
|
|
||||||
|
递归。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ListNode deleteDuplication(ListNode pHead) {
|
public ListNode deleteDuplication(ListNode pHead) {
|
||||||
if (pHead == null) return null;
|
if (pHead == null) return null;
|
||||||
@ -1009,6 +1046,10 @@ public ArrayList<Integer> printMatrix(int[][] matrix) {
|
|||||||
|
|
||||||
## 30. 包含 min 函数的栈
|
## 30. 包含 min 函数的栈
|
||||||
|
|
||||||
|
**题目描述**
|
||||||
|
|
||||||
|
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的 min 函数。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private Stack<Integer> stack = new Stack<>();
|
private Stack<Integer> stack = new Stack<>();
|
||||||
private Stack<Integer> minStack = new Stack<>();
|
private Stack<Integer> minStack = new Stack<>();
|
||||||
@ -1369,6 +1410,12 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuffer s) {
|
|||||||
|
|
||||||
## 39. 数组中出现次数超过一半的数字
|
## 39. 数组中出现次数超过一半的数字
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
多数投票问题,可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(n)。
|
||||||
|
|
||||||
|
使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不想等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0 ,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int MoreThanHalfNum_Solution(int[] nums) {
|
public int MoreThanHalfNum_Solution(int[] nums) {
|
||||||
int cnt = 1, num = nums[0];
|
int cnt = 1, num = nums[0];
|
||||||
@ -1813,6 +1860,8 @@ private void merge(int[] nums, int start, int mid, int end) {
|
|||||||
|
|
||||||
## 52. 两个链表的第一个公共结点
|
## 52. 两个链表的第一个公共结点
|
||||||
|
|
||||||
|
**题目描述**
|
||||||
|
|
||||||
```html
|
```html
|
||||||
A: a1 → a2
|
A: a1 → a2
|
||||||
↘
|
↘
|
||||||
@ -1821,6 +1870,8 @@ A: a1 → a2
|
|||||||
B: b1 → b2 → b3
|
B: b1 → b2 → b3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
|
设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
|
||||||
|
|
||||||
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
|
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
|
||||||
@ -1840,23 +1891,56 @@ public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
|
|||||||
|
|
||||||
## 53 数字在排序数组中出现的次数
|
## 53 数字在排序数组中出现的次数
|
||||||
|
|
||||||
|
**题目描述**
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
1, 2, 3, 3, 3, 3, 4, 6
|
||||||
|
3
|
||||||
|
Output:
|
||||||
|
4
|
||||||
|
````
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
可以用二分查找找出数字在数组的最左端和最右端。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int GetNumberOfK(int[] array, int num) {
|
public int GetNumberOfK(int[] nums, int K) {
|
||||||
int l = 0, h = array.length - 1;
|
int first = getFirstK(nums, K);
|
||||||
// 先找出 num 在数组最左端的位置,可以控制二分查找结束时 l 指向该位置
|
int last = getLastK(nums, K);
|
||||||
|
return first == -1 || last == -1 ? 0 : last - first + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getFirstK(int[] nums, int K) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
while (l <= h) {
|
while (l <= h) {
|
||||||
int m = l + (h - l) / 2;
|
int m = l + (h - l) / 2;
|
||||||
if (array[m] >= num) h = m - 1;
|
if (nums[m] >= K) h = m - 1;
|
||||||
else l = m + 1;
|
else l = m + 1;
|
||||||
}
|
}
|
||||||
int cnt = 0;
|
if (l > nums.length - 1 || nums[l] != K) return -1;
|
||||||
while (l < array.length && array[l++] == num) cnt++;
|
return l;
|
||||||
return cnt;
|
}
|
||||||
|
|
||||||
|
private int getLastK(int[] nums, int K) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l <= h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (nums[m] > K) h = m - 1;
|
||||||
|
else l = m + 1;
|
||||||
|
}
|
||||||
|
if (h < 0 || nums[h] != K) return -1;
|
||||||
|
return h;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 54. 二叉搜索树的第 k 个结点
|
## 54. 二叉搜索树的第 k 个结点
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
利用二叉搜索数中序遍历有序的特点。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
TreeNode ret;
|
TreeNode ret;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
@ -1917,6 +2001,12 @@ public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) {
|
|||||||
|
|
||||||
输入一个递增排序的数组和一个数字 S,在数组中查找两个数,是的他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最小的。
|
输入一个递增排序的数组和一个数字 S,在数组中查找两个数,是的他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最小的。
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
使用双指针,一个指针指向元素较小的值,一个指针指向元素较大的值。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
|
||||||
|
|
||||||
|
如果两个指针指向元素的和 sum == target,那么得到要求的结果;如果 sum > target,移动较大的元素,使 sum 变小一些;如果 sum < target,移动较小的元素,使 sum 变大一些。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
|
public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
|
||||||
int i = 0, j = array.length - 1;
|
int i = 0, j = array.length - 1;
|
||||||
|
@ -839,9 +839,9 @@ if (uniqueInstance == null) {
|
|||||||
|
|
||||||
有非常多的家电,并且之后会增加家电。
|
有非常多的家电,并且之后会增加家电。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//7b8f0d8e-a4fa-4c9d-b9a0-3e6a11cb3e33.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//f6be22cb-d64f-4ee5-87b7-cbc4e6255c0e.jpg"/> </div><br>
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//c3ca36b2-8459-4cf1-98b0-cc95a0e94f20.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//5b832bde-d05e-42db-b648-42e274571ad9.jpg"/> </div><br>
|
||||||
|
|
||||||
**2. 模式定义**
|
**2. 模式定义**
|
||||||
|
|
||||||
@ -857,11 +857,11 @@ if (uniqueInstance == null) {
|
|||||||
|
|
||||||
- RemoteLoader 是客户端,注意它与 RemoteControl 的区别。因为 RemoteControl 不能主动地调用自身的方法,因此也就不能当成是客户端。客户端好比人,只有人才能去真正去使用遥控器。
|
- RemoteLoader 是客户端,注意它与 RemoteControl 的区别。因为 RemoteControl 不能主动地调用自身的方法,因此也就不能当成是客户端。客户端好比人,只有人才能去真正去使用遥控器。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//5ef94f62-98ce-464d-a646-842d9c72c8b8.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//b7b1f5c6-ff8a-4353-8060-44bbc4b9e02e.jpg"/> </div><br>
|
||||||
|
|
||||||
**4. 模式类图**
|
**4. 模式类图**
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//1e09d75f-6268-4425-acf8-8ecd1b4a0ef3.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//26ccd069-55ec-4a28-aeb3-025e39e5810f.jpg"/> </div><br>
|
||||||
|
|
||||||
**5. 代码实现**
|
**5. 代码实现**
|
||||||
|
|
||||||
@ -948,7 +948,7 @@ Light is on!
|
|||||||
|
|
||||||
将一个类的接口,转换为客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
|
将一个类的接口,转换为客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//8e8ba824-7a9e-4934-a212-e6a41dcc1602.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//c484b07d-be3d-4699-9e28-f035de8a274c.jpg"/> </div><br>
|
||||||
|
|
||||||
**2. 模式类图**
|
**2. 模式类图**
|
||||||
|
|
||||||
@ -962,11 +962,11 @@ Light is on!
|
|||||||
|
|
||||||
鸭子(Duck)和火鸡(Turkey)拥有不同的叫声,Duck 调用的是 quack() 方法,而 Turkey 调用 gobble() 方法。
|
鸭子(Duck)和火鸡(Turkey)拥有不同的叫声,Duck 调用的是 quack() 方法,而 Turkey 调用 gobble() 方法。
|
||||||
|
|
||||||
要求将 Turkey 的 gobble() 方法适配成 Duck 的 quack() 方法。
|
要求将 Turkey 的 gobble() 方法适配成 Duck 的 quack() 方法,从而让火鸡冒充鸭子。
|
||||||
|
|
||||||
**4. 解决方案类图**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//1a511c76-bb6b-40ab-b8aa-39eeb619d673.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//b8ceb9db-180e-4d01-932c-593fa2a6f515.jpg"/> </div><br>
|
||||||
|
|
||||||
**5. 代码实现**
|
**5. 代码实现**
|
||||||
|
|
||||||
@ -1022,6 +1022,10 @@ public class DuckTestDrive {
|
|||||||
gobble!
|
gobble!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**6. Enumration 适配成 Iterator**
|
||||||
|
|
||||||
|
<div align="center"> <img src="../pics//aa340e1a-f366-436b-a5a5-29a90425c10d.png"/> </div><br>
|
||||||
|
|
||||||
# 外观模式
|
# 外观模式
|
||||||
|
|
||||||
**1. 模式定义**
|
**1. 模式定义**
|
||||||
@ -1040,7 +1044,7 @@ gobble!
|
|||||||
|
|
||||||
**4. 解决方案类图**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//25387681-89f8-4365-a2fa-83b86449ee84.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//a0339a9f-f44f-4e37-a37f-169bc735536d.jpg"/> </div><br>
|
||||||
|
|
||||||
**5. 设计原则**
|
**5. 设计原则**
|
||||||
|
|
||||||
@ -1062,7 +1066,7 @@ gobble!
|
|||||||
|
|
||||||
模板方法 templateMethod() 定义了算法的骨架,确定了 primitiveOperation1() 和 primitiveOperation2() 方法执行的顺序,而 primitiveOperation1() 和 primitiveOperation2() 让子类去实现。
|
模板方法 templateMethod() 定义了算法的骨架,确定了 primitiveOperation1() 和 primitiveOperation2() 方法执行的顺序,而 primitiveOperation1() 和 primitiveOperation2() 让子类去实现。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//ed62f400-192c-4185-899b-187958201f0c.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//87ffaf7f-4aa5-4da0-af84-994de62fa440.jpg"/> </div><br>
|
||||||
|
|
||||||
**3. 问题描述**
|
**3. 问题描述**
|
||||||
|
|
||||||
@ -1082,7 +1086,7 @@ gobble!
|
|||||||
|
|
||||||
**6. 钩子**
|
**6. 钩子**
|
||||||
|
|
||||||
钩子(hock):某些步骤在不同实现中可有可无,可以先定义一个什么都不做的方法,把它加到模板方法中,如果子类需要它就覆盖默认实现并加上自己的实现。
|
某些步骤在不同实现中可有可无,可以先定义一个什么都不做的方法,把它加到模板方法中,如果子类需要它就覆盖默认实现并加上自己的实现。
|
||||||
|
|
||||||
**7. 代码实现**
|
**7. 代码实现**
|
||||||
|
|
||||||
@ -1334,7 +1338,7 @@ public class Client {
|
|||||||
|
|
||||||
组合类拥有一个组件对象,因此组合类的操作可以委托给组件对象去处理,而组件对象可以是另一个组合类或者叶子类。
|
组合类拥有一个组件对象,因此组合类的操作可以委托给组件对象去处理,而组件对象可以是另一个组合类或者叶子类。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//f99c019e-7e91-4c2e-b94d-b031c402dcb5.jpg"/> </div><br>
|
<div align="center"> <img src="../pics//cf08a51d-14c0-4bfc-863b-c8672d9c2b02.jpg"/> </div><br>
|
||||||
|
|
||||||
**4. 代码实现**
|
**4. 代码实现**
|
||||||
|
|
||||||
@ -1455,9 +1459,9 @@ Context 的 request() 方法委托给 State 对象去处理。当 Context 组合
|
|||||||
|
|
||||||
但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。
|
但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。
|
||||||
|
|
||||||
所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,主要必须要是在运行过程中。
|
所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
|
||||||
|
|
||||||
状态模式主要是用来解决状态转移的问题,当状态发生庄毅了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 需要使用哪个算法。
|
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 需要使用哪个算法。
|
||||||
|
|
||||||
**4. 问题描述**
|
**4. 问题描述**
|
||||||
|
|
||||||
@ -1477,7 +1481,7 @@ Context 的 request() 方法委托给 State 对象去处理。当 Context 组合
|
|||||||
|
|
||||||
糖果销售机即 Context。
|
糖果销售机即 Context。
|
||||||
|
|
||||||
下面的实现中每个 State 都组合了 Context 对象,这是因为状态转移的操作在 State 对象中,而状态转移过程又必须改变 Context 对象的 state 对象,因此 State 必须拥有 Context 对象。
|
下面的实现中每个 State 都组合了 Context 对象,这是因为状态转移的操作在 State 对象中,而状态转移过程又必须改变 Context 对象的 state 对象,因此 State 必须组合 Context 对象。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface State {
|
public interface State {
|
||||||
@ -1504,6 +1508,7 @@ public interface State {
|
|||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
public class HasQuarterState implements State{
|
public class HasQuarterState implements State{
|
||||||
|
|
||||||
private GumballMachine gumballMachine;
|
private GumballMachine gumballMachine;
|
||||||
|
|
||||||
public HasQuarterState(GumballMachine gumballMachine){
|
public HasQuarterState(GumballMachine gumballMachine){
|
||||||
@ -1535,6 +1540,7 @@ public class HasQuarterState implements State{
|
|||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
public class NoQuarterState implements State {
|
public class NoQuarterState implements State {
|
||||||
|
|
||||||
GumballMachine gumballMachine;
|
GumballMachine gumballMachine;
|
||||||
|
|
||||||
public NoQuarterState(GumballMachine gumballMachine) {
|
public NoQuarterState(GumballMachine gumballMachine) {
|
||||||
@ -1595,6 +1601,7 @@ public class SoldOutState implements State {
|
|||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
public class SoldState implements State {
|
public class SoldState implements State {
|
||||||
|
|
||||||
GumballMachine gumballMachine;
|
GumballMachine gumballMachine;
|
||||||
|
|
||||||
public SoldState(GumballMachine gumballMachine) {
|
public SoldState(GumballMachine gumballMachine) {
|
||||||
@ -1630,6 +1637,7 @@ public class SoldState implements State {
|
|||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
public class GumballMachine {
|
public class GumballMachine {
|
||||||
|
|
||||||
private State soldOutState;
|
private State soldOutState;
|
||||||
private State noQuarterState;
|
private State noQuarterState;
|
||||||
private State hasQuarterState;
|
private State hasQuarterState;
|
||||||
@ -1699,6 +1707,7 @@ public class GumballMachine {
|
|||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
public class GumballMachineTestDrive {
|
public class GumballMachineTestDrive {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
GumballMachine gumballMachine = new GumballMachine(5);
|
GumballMachine gumballMachine = new GumballMachine(5);
|
||||||
|
|
||||||
@ -1778,7 +1787,7 @@ No gumball dispensed
|
|||||||
|
|
||||||
过度使用设计模式可能导致代码被过度工程化,应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它。
|
过度使用设计模式可能导致代码被过度工程化,应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它。
|
||||||
|
|
||||||
反模式:不好的解决方案来解决一个问题。主要作用是为了警告不要使用这些解决方案。
|
反模式:不好的解决方案来解决一个问题。主要作用是为了警告人们不要使用这些解决方案。
|
||||||
|
|
||||||
模式分类:
|
模式分类:
|
||||||
|
|
||||||
|
180
notes/面向对象思想.md
@ -1,30 +1,41 @@
|
|||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [S.O.L.I.D](#solid)
|
* [设计原则](#设计原则)
|
||||||
* [1. 单一责任原则](#1-单一责任原则)
|
* [1. S.O.L.I.D](#1-solid)
|
||||||
* [2. 开放封闭原则](#2-开放封闭原则)
|
* [1.1 单一责任原则](#11-单一责任原则)
|
||||||
* [3. 里氏替换原则](#3-里氏替换原则)
|
* [1.2 开放封闭原则](#12-开放封闭原则)
|
||||||
* [4. 接口分离原则](#4-接口分离原则)
|
* [1.3 里氏替换原则](#13-里氏替换原则)
|
||||||
* [5. 依赖倒置原则](#5-依赖倒置原则)
|
* [1.4 接口分离原则](#14-接口分离原则)
|
||||||
* [其他常见原则](#其他常见原则)
|
* [1.5 依赖倒置原则](#15-依赖倒置原则)
|
||||||
* [1. 迪米特法则](#1-迪米特法则)
|
* [2. 其他常见原则](#2-其他常见原则)
|
||||||
* [2. 合成复用原则](#2-合成复用原则)
|
* [2.1 迪米特法则](#21-迪米特法则)
|
||||||
* [3. 共同封闭原则](#3-共同封闭原则)
|
* [2.2 合成复用原则](#22-合成复用原则)
|
||||||
* [4. 稳定抽象原则](#4-稳定抽象原则)
|
* [2.3 共同封闭原则](#23-共同封闭原则)
|
||||||
* [5. 稳定依赖原则](#5-稳定依赖原则)
|
* [2.4 稳定抽象原则](#24-稳定抽象原则)
|
||||||
* [封装、继承、多态](#封装继承多态)
|
* [2.5 稳定依赖原则](#25-稳定依赖原则)
|
||||||
|
* [三大特性](#三大特性)
|
||||||
* [1. 封装](#1-封装)
|
* [1. 封装](#1-封装)
|
||||||
* [2. 继承](#2-继承)
|
* [2. 继承](#2-继承)
|
||||||
* [3. 多态](#3-多态)
|
* [3. 多态](#3-多态)
|
||||||
* [UML](#uml)
|
* [UML](#uml)
|
||||||
* [1. 类图](#1-类图)
|
* [1. 类图](#1-类图)
|
||||||
|
* [1.1 继承相关](#11-继承相关)
|
||||||
|
* [1.2 整体和部分](#12-整体和部分)
|
||||||
|
* [1.3 相互联系](#13-相互联系)
|
||||||
* [2. 时序图](#2-时序图)
|
* [2. 时序图](#2-时序图)
|
||||||
|
* [2.1 定义](#21-定义)
|
||||||
|
* [2.2 赤壁之战时序图](#22-赤壁之战时序图)
|
||||||
|
* [2.3 活动图、时序图之间的关系](#23-活动图时序图之间的关系)
|
||||||
|
* [2.4 类图与时序图的关系](#24-类图与时序图的关系)
|
||||||
|
* [2.5 时序图的组成](#25-时序图的组成)
|
||||||
* [参考资料](#参考资料)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
# S.O.L.I.D
|
# 设计原则
|
||||||
|
|
||||||
S.O.L.I.D 是面向对象设计和编程 (OOD&OOP) 中几个重要编码原则 (Programming Priciple) 的首字母缩写。
|
设计原则可以帮助我们避免那些糟糕的设计,这些原则被归纳在《敏捷软件开发:原则、模式与实践》这本书中。
|
||||||
|
|
||||||
|
## 1. S.O.L.I.D
|
||||||
|
|
||||||
| 简写 | 全拼 | 中文翻译 |
|
| 简写 | 全拼 | 中文翻译 |
|
||||||
| -- | -- | -- |
|
| -- | -- | -- |
|
||||||
@ -34,29 +45,50 @@ S.O.L.I.D 是面向对象设计和编程 (OOD&OOP) 中几个重要编码原则 (
|
|||||||
| ISP | The Interface Segregation Principle | 接口分离原则 |
|
| ISP | The Interface Segregation Principle | 接口分离原则 |
|
||||||
| DIP | The Dependency Inversion Principle | 依赖倒置原则 |
|
| DIP | The Dependency Inversion Principle | 依赖倒置原则 |
|
||||||
|
|
||||||
|
### 1.1 单一责任原则
|
||||||
|
|
||||||
## 1. 单一责任原则
|
**修改一个类的原因应该只有一个。**
|
||||||
|
|
||||||
当需要修改某个类的时候原因有且只有一个。换句话说就是让一个类只做一种类型责任,当这个类需要承当其他类型的责任的时候,就需要分解这个类。
|
换句话说就是让一个类只负责一件事,当这个类需要做过多事情的时候,就需要分解这个类。
|
||||||
|
|
||||||
## 2. 开放封闭原则
|
如果一个类承担的职责过多,就等于把这些职责耦合在了一起,一个职责的变化可能会削弱这个类完成其它职责的能力。
|
||||||
|
|
||||||
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
|
### 1.2 开放封闭原则
|
||||||
|
|
||||||
## 3. 里氏替换原则
|
**类应该对扩展开放,对修改关闭。**
|
||||||
|
|
||||||
当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有 is-a 关系。
|
扩展就是添加新功能的意思,因此该原则要求在添加新功能时不需要修改代码。
|
||||||
|
|
||||||
## 4. 接口分离原则
|
符合开闭原则最典型的设计模式是装饰者模式,它可以动态地将责任附加到对象上,而不用去修改类的代码。
|
||||||
|
|
||||||
不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。
|
### 1.3 里氏替换原则
|
||||||
|
|
||||||
## 5. 依赖倒置原则
|
**子类对象必须能够替换掉所有父类对象。**
|
||||||
|
|
||||||
1. 高层模块不应该依赖于低层模块,二者都应该依赖于抽象
|
继承是一种 IS-A 关系,子类需要能够当成父类来使用,并且需要比父类更特殊。
|
||||||
2. 抽象不应该依赖于细节,细节应该依赖于抽象
|
|
||||||
|
|
||||||
# 其他常见原则
|
如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度。
|
||||||
|
|
||||||
|
### 1.4 接口分离原则
|
||||||
|
|
||||||
|
**不应该强迫客户依赖于它们不用的方法。**
|
||||||
|
|
||||||
|
因此使用多个专门的接口比使用单一的总接口总要好。
|
||||||
|
|
||||||
|
### 1.5 依赖倒置原则
|
||||||
|
|
||||||
|
- **高层模块不应该依赖于低层模块,二者都应该依赖于抽象**
|
||||||
|
- **抽象不应该依赖于细节,细节应该依赖于抽象**
|
||||||
|
|
||||||
|
高层模块包含一个应用程序中重要的策略选择和业务模块,如果高层模块依赖于底层模块,那么底层模块的改动就会直接影响到高层模块,从而迫使高层模块也需要改动。
|
||||||
|
|
||||||
|
依赖于抽象意味着:
|
||||||
|
|
||||||
|
- 任何变量都不应该持有一个指向具体类的指针或者引用;
|
||||||
|
- 任何类都不应该从具体类派生;
|
||||||
|
- 任何方法都不应该覆写它的任何基类中的已经实现的方法。
|
||||||
|
|
||||||
|
## 2. 其他常见原则
|
||||||
|
|
||||||
除了上述的经典原则,在实际开发中还有下面这些常见的设计原则。
|
除了上述的经典原则,在实际开发中还有下面这些常见的设计原则。
|
||||||
|
|
||||||
@ -68,44 +100,41 @@ S.O.L.I.D 是面向对象设计和编程 (OOD&OOP) 中几个重要编码原则 (
|
|||||||
|SAP| The Stable Abstractions Principle | 稳定抽象原则 |
|
|SAP| The Stable Abstractions Principle | 稳定抽象原则 |
|
||||||
|SDP| The Stable Dependencies Principle | 稳定依赖原则 |
|
|SDP| The Stable Dependencies Principle | 稳定依赖原则 |
|
||||||
|
|
||||||
## 1. 迪米特法则
|
### 2.1 迪米特法则
|
||||||
|
|
||||||
迪米特法则又叫作最少知道原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。
|
迪米特法则又叫作最少知道原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。
|
||||||
|
|
||||||
## 2. 合成复用原则
|
### 2.2 合成复用原则
|
||||||
|
|
||||||
尽量使用对象组合,而不是继承来达到复用的目的。
|
尽量使用对象组合,而不是继承来达到复用的目的。
|
||||||
|
|
||||||
## 3. 共同封闭原则
|
### 2.3 共同封闭原则
|
||||||
|
|
||||||
一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
|
一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
|
||||||
|
|
||||||
## 4. 稳定抽象原则
|
### 2.4 稳定抽象原则
|
||||||
|
|
||||||
最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
|
最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
|
||||||
|
|
||||||
## 5. 稳定依赖原则
|
### 2.5 稳定依赖原则
|
||||||
|
|
||||||
包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。
|
包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。
|
||||||
|
|
||||||
# 封装、继承、多态
|
# 三大特性
|
||||||
|
|
||||||
封装、继承、多态是面向对象的三大特性。
|
|
||||||
|
|
||||||
## 1. 封装
|
## 1. 封装
|
||||||
|
|
||||||
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户是无需知道对象内部的细节,但可以通过该对象对外的提供的接口来访问该对象。
|
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
|
||||||
|
|
||||||
封装有三大好处:
|
封装有三大好处:
|
||||||
|
|
||||||
1. 良好的封装能够减少耦合。
|
1. 减少耦合
|
||||||
2. 类内部的结构可以自由修改。
|
2. 隐藏内部细节,因此内部结构可以自由修改
|
||||||
3. 可以对成员进行更精确的控制。
|
3. 可以对成员进行更精确的控制
|
||||||
4. 隐藏信息,实现细节。
|
|
||||||
|
|
||||||
以下 Person 类封装 name、gender、age 等属性,外界只能通过 get() 方法获取一个 Person 对象的 name 属性和 gender 属性,而无法获取 age 属性,但是 age 属性可以供 work() 方法使用。
|
以下 Person 类封装 name、gender、age 等属性,外界只能通过 get() 方法获取一个 Person 对象的 name 属性和 gender 属性,而无法获取 age 属性,但是 age 属性可以供 work() 方法使用。
|
||||||
|
|
||||||
注意到 gender 属性使用 int 数据类型进行存储,封装使得用户注意不到这种实现细节。并且在需要修改使用的数据类型时,也可以在不影响客户端代码的情况下进行。
|
注意到 gender 属性使用 int 数据类型进行存储,封装使得用户注意不到这种实现细节。并且在需要修改 gender 属性使用的数据类型时,也可以在不影响客户端代码的情况下进行。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Person {
|
public class Person {
|
||||||
@ -125,7 +154,7 @@ public class Person {
|
|||||||
if(18 <= age && age <= 50) {
|
if(18 <= age && age <= 50) {
|
||||||
System.out.println(name + " is working very hard!");
|
System.out.println(name + " is working very hard!");
|
||||||
} else {
|
} else {
|
||||||
System.out.println(name + " can't work!");
|
System.out.println(name + " can't work any more!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,23 +162,27 @@ public class Person {
|
|||||||
|
|
||||||
## 2. 继承
|
## 2. 继承
|
||||||
|
|
||||||
继承实现了 **is-a** 关系,例如 Cat 和 Animal 就是一种 is-a 关系,因此可以将 Cat 继承自 Animal,从而获得 Animal 非 private 的属性和方法。
|
继承实现了 **IS-A** 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
|
||||||
|
|
||||||
Cat 可以当做 Animal 来使用,也就是可以使用 Animal 引用 Cat 对象,这种子类转换为父类称为 **向上转型** 。
|
Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 **向上转型** 。
|
||||||
|
|
||||||
继承应该遵循里氏替换原则:当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有 is-a 关系。
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Animal animal = new Cat();
|
Animal animal = new Cat();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
|
||||||
|
|
||||||
## 3. 多态
|
## 3. 多态
|
||||||
|
|
||||||
多态分为编译时多态和运行时多态。编译时多态主要指方法的重装,运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定。
|
多态分为编译时多态和运行时多态。编译时多态主要指方法的重载,运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定。
|
||||||
|
|
||||||
多态有三个条件:1. 继承;2. 覆盖父类方法;3. 向上转型。
|
运行时多态有三个条件:
|
||||||
|
|
||||||
下面的代码中,乐器类(Instrument)有两个子类:Wind 和 Percussion,它们都覆盖了 play() 方法,并且在 main() 方法中使用父类 Instrument 来引用 Wind 和 Percussion 对象。在 Instrument 引用调用 play() 方法时,会执行实际引用对象所在类的 play() 方法,而不是 Instrument 类的方法。
|
1. 继承
|
||||||
|
2. 覆盖
|
||||||
|
3. 向上转型
|
||||||
|
|
||||||
|
下面的代码中,乐器类(Instrument)有两个子类:Wind 和 Percussion,它们都覆盖了父类的 play() 方法,并且在 main() 方法中使用父类 Instrument 来引用 Wind 和 Percussion 对象。在 Instrument 引用调用 play() 方法时,会执行实际引用对象所在类的 play() 方法,而不是 Instrument 类的方法。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Instrument {
|
public class Instrument {
|
||||||
@ -180,54 +213,51 @@ public class Music {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# UML
|
# UML
|
||||||
|
|
||||||
## 1. 类图
|
## 1. 类图
|
||||||
|
|
||||||
**1.1 继承相关**
|
### 1.1 继承相关
|
||||||
|
|
||||||
继承有两种形式 : 泛化(generalize)和实现(realize),表现为 is-a 关系。
|
继承有两种形式 : 泛化(Generalize)和实现(Realize),表现为 IS-A 关系。
|
||||||
|
|
||||||
① 泛化关系 (generalization)
|
**泛化关系 (Generalize)**
|
||||||
|
|
||||||
从具体类中继承
|
从具体类中继承。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//29badd92-109f-4f29-abb9-9857f5973928.png"/> </div><br>
|
<div align="center"> <img src="../pics//29badd92-109f-4f29-abb9-9857f5973928.png"/> </div><br>
|
||||||
|
|
||||||
② 实现关系 (realize)
|
**实现关系 (Realize)**
|
||||||
|
|
||||||
从抽象类或者接口中继承
|
从抽象类或者接口中继承。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//4b16e1d3-3a60-472c-9756-2f31b1c48abe.png"/> </div><br>
|
<div align="center"> <img src="../pics//4b16e1d3-3a60-472c-9756-2f31b1c48abe.png"/> </div><br>
|
||||||
|
|
||||||
**1.2 整体和部分**
|
### 1.2 整体和部分
|
||||||
|
|
||||||
① 聚合关系 (aggregation)
|
**聚合关系 (Aggregation)**
|
||||||
|
|
||||||
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。以下表示 B 由 A 组成:
|
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。以下表示 B 由 A 组成:
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//34259bb8-ca3a-4872-8771-9e946782d9c3.png"/> </div><br>
|
<div align="center"> <img src="../pics//34259bb8-ca3a-4872-8771-9e946782d9c3.png"/> </div><br>
|
||||||
|
|
||||||
② 组合关系 (composition)
|
**组合关系 (Composition)**
|
||||||
|
|
||||||
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
|
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png"/> </div><br>
|
<div align="center"> <img src="../pics//7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png"/> </div><br>
|
||||||
|
|
||||||
**1.3 相互联系**
|
### 1.3 相互联系
|
||||||
|
|
||||||
① 关联关系 (association)
|
**关联关系 (Association)**
|
||||||
|
|
||||||
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。
|
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//4ccd294c-d6b2-421b-839e-d88336ff5fb7.png"/> </div><br>
|
<div align="center"> <img src="../pics//4ccd294c-d6b2-421b-839e-d88336ff5fb7.png"/> </div><br>
|
||||||
|
|
||||||
② 依赖关系 (dependency)
|
**依赖关系 (Dependency)**
|
||||||
|
|
||||||
和关联关系不同的是 , 依赖关系是在运行过程中起作用的。一般依赖作为类的构造器或者方法的参数传入。双向依赖时一种不好的设计。
|
和关联关系不同的是 , 依赖关系是在运行过程中起作用的。一般依赖作为类的构造器或者方法的参数传入。双向依赖时一种不好的设计。
|
||||||
|
|
||||||
@ -235,13 +265,11 @@ public class Music {
|
|||||||
|
|
||||||
## 2. 时序图
|
## 2. 时序图
|
||||||
|
|
||||||
http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html
|
### 2.1 定义
|
||||||
|
|
||||||
**2.1 定义**
|
|
||||||
|
|
||||||
时序图描述了对象之间传递消息的时间顺序,它用来表示用例的行为顺序。它的主要作用是通过对象间的交互来描述用例(注意是对象),从而寻找类的操作。
|
时序图描述了对象之间传递消息的时间顺序,它用来表示用例的行为顺序。它的主要作用是通过对象间的交互来描述用例(注意是对象),从而寻找类的操作。
|
||||||
|
|
||||||
**2.2 赤壁之战时序图**
|
### 2.2 赤壁之战时序图
|
||||||
|
|
||||||
从虚线从上往下表示时间的推进。
|
从虚线从上往下表示时间的推进。
|
||||||
|
|
||||||
@ -273,19 +301,19 @@ public class 孙权 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**2.3 活动图、时序图之间的关系**
|
### 2.3 活动图、时序图之间的关系
|
||||||
|
|
||||||
活动图示从用户的角度来描述用例;
|
活动图示从用户的角度来描述用例;
|
||||||
|
|
||||||
时序图是从计算机的角度(对象间的交互)描述用例。
|
时序图是从计算机的角度(对象间的交互)描述用例。
|
||||||
|
|
||||||
**2.4 类图与时序图的关系**
|
### 2.4 类图与时序图的关系
|
||||||
|
|
||||||
类图描述系统的静态结构,时序图描述系统的动态行为。
|
类图描述系统的静态结构,时序图描述系统的动态行为。
|
||||||
|
|
||||||
**2.5 时序图的组成**
|
### 2.5 时序图的组成
|
||||||
|
|
||||||
① 对象
|
**对象**
|
||||||
|
|
||||||
有三种表现形式
|
有三种表现形式
|
||||||
|
|
||||||
@ -297,13 +325,13 @@ public class 孙权 {
|
|||||||
|
|
||||||
2. 把初始化整个交互活动的对象(有时是一个参与者)放置在最左边。
|
2. 把初始化整个交互活动的对象(有时是一个参与者)放置在最左边。
|
||||||
|
|
||||||
② 生命线
|
**生命线**
|
||||||
|
|
||||||
生命线从对象的创建开始到对象销毁时终止
|
生命线从对象的创建开始到对象销毁时终止
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png"/> </div><br>
|
<div align="center"> <img src="../pics//b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png"/> </div><br>
|
||||||
|
|
||||||
③ 消息
|
**消息**
|
||||||
|
|
||||||
对象之间的交互式通过发送消息来实现的。
|
对象之间的交互式通过发送消息来实现的。
|
||||||
|
|
||||||
@ -323,16 +351,16 @@ public class 孙权 {
|
|||||||
|
|
||||||
4\. 返回消息,可选。
|
4\. 返回消息,可选。
|
||||||
|
|
||||||
④ 激活
|
**激活**
|
||||||
|
|
||||||
生命线上的方框表示激活状态,其它时间处于休眠状态。
|
生命线上的方框表示激活状态,其它时间处于休眠状态。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png"/> </div><br>
|
<div align="center"> <img src="../pics//6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
# 参考资料
|
# 参考资料
|
||||||
|
|
||||||
- Java 编程思想
|
- Java 编程思想
|
||||||
|
- 敏捷软件开发:原则、模式与实践
|
||||||
- [面向对象设计的 SOLID 原则](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html)
|
- [面向对象设计的 SOLID 原则](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html)
|
||||||
- [看懂 UML 类图和时序图](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization)
|
- [看懂 UML 类图和时序图](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization)
|
||||||
- [UML 系列——时序图(顺序图)sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html)
|
- [UML 系列——时序图(顺序图)sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html)
|
||||||
|
BIN
pics/26ccd069-55ec-4a28-aeb3-025e39e5810f.jpg
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
pics/2a398239-ee47-4ea1-b2d8-0ced638839ef.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
pics/5b832bde-d05e-42db-b648-42e274571ad9.jpg
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
pics/72f9bc11-06a9-40b4-8939-14f72e5cb4c3.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
pics/87ffaf7f-4aa5-4da0-af84-994de62fa440.jpg
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
pics/a0339a9f-f44f-4e37-a37f-169bc735536d.jpg
Normal file
After Width: | Height: | Size: 246 KiB |
BIN
pics/aa340e1a-f366-436b-a5a5-29a90425c10d.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
pics/b7b1f5c6-ff8a-4353-8060-44bbc4b9e02e.jpg
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
pics/b8ceb9db-180e-4d01-932c-593fa2a6f515.jpg
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
pics/c484b07d-be3d-4699-9e28-f035de8a274c.jpg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
pics/cf08a51d-14c0-4bfc-863b-c8672d9c2b02.jpg
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pics/f6be22cb-d64f-4ee5-87b7-cbc4e6255c0e.jpg
Normal file
After Width: | Height: | Size: 160 KiB |