auto commit
This commit is contained in:
@ -98,7 +98,9 @@ public static synchronized Singleton getUniqueInstance() {
|
||||
|
||||
(三)饿汉式-线程安全
|
||||
|
||||
线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。
|
||||
线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。
|
||||
|
||||
但是直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。
|
||||
|
||||
```java
|
||||
private static Singleton uniqueInstance = new Singleton();
|
||||
@ -106,7 +108,7 @@ private static Singleton uniqueInstance = new Singleton();
|
||||
|
||||
(四)双重校验锁-线程安全
|
||||
|
||||
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
|
||||
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
|
||||
|
||||
双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
|
||||
|
||||
@ -131,7 +133,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
|
||||
if (uniqueInstance == null) {
|
||||
@ -157,7 +159,7 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的。`uniqueIns
|
||||
|
||||
这种方式不仅具有延迟初始化的好处,而且由虚拟机提供了对线程安全的支持。
|
||||
|
||||
```source-java
|
||||
```java
|
||||
public class Singleton {
|
||||
|
||||
private Singleton() {
|
||||
@ -299,7 +301,7 @@ public class Client {
|
||||
|
||||
### 意图
|
||||
|
||||
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化推迟到子类。
|
||||
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
|
||||
|
||||
### 类图
|
||||
|
||||
@ -1851,11 +1853,7 @@ No gumball dispensed
|
||||
|
||||
### 与状态模式的比较
|
||||
|
||||
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。
|
||||
|
||||
但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。
|
||||
|
||||
所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
|
||||
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
|
||||
|
||||
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
|
||||
|
||||
@ -1969,7 +1967,7 @@ public abstract class CaffeineBeverage {
|
||||
```
|
||||
|
||||
```java
|
||||
public class Coffee extends CaffeineBeverage{
|
||||
public class Coffee extends CaffeineBeverage {
|
||||
@Override
|
||||
void brew() {
|
||||
System.out.println("Coffee.brew");
|
||||
@ -1983,7 +1981,7 @@ public class Coffee extends CaffeineBeverage{
|
||||
```
|
||||
|
||||
```java
|
||||
public class Tea extends CaffeineBeverage{
|
||||
public class Tea extends CaffeineBeverage {
|
||||
@Override
|
||||
void brew() {
|
||||
System.out.println("Tea.brew");
|
||||
@ -2238,7 +2236,7 @@ Number of items: 6
|
||||
|
||||
### 意图
|
||||
|
||||
使用什么都不做的空对象来替代 NULL。
|
||||
使用什么都不做的空对象来代替 NULL。
|
||||
|
||||
一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
|
||||
|
||||
@ -2393,7 +2391,7 @@ public abstract class TV {
|
||||
```
|
||||
|
||||
```java
|
||||
public class Sony extends TV{
|
||||
public class Sony extends TV {
|
||||
@Override
|
||||
public void on() {
|
||||
System.out.println("Sony.on()");
|
||||
@ -2412,7 +2410,7 @@ public class Sony extends TV{
|
||||
```
|
||||
|
||||
```java
|
||||
public class RCA extends TV{
|
||||
public class RCA extends TV {
|
||||
@Override
|
||||
public void on() {
|
||||
System.out.println("RCA.on()");
|
||||
@ -2551,9 +2549,6 @@ public abstract class Component {
|
||||
```
|
||||
|
||||
```java
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Composite extends Component {
|
||||
|
||||
private List<Component> child;
|
||||
@ -2659,7 +2654,7 @@ Composite:root
|
||||
|
||||
### 类图
|
||||
|
||||
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
|
||||
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
|
||||
|
||||
<div align="center"> <img src="../pics//137c593d-0a9e-47b8-a9e6-b71f540b82dd.png"/> </div><br>
|
||||
|
||||
@ -2770,7 +2765,7 @@ public class Client {
|
||||
|
||||
### 实现
|
||||
|
||||
观看电影需要操作很多电器,使用外观模式可以实现一键看电影功能。
|
||||
观看电影需要操作很多电器,使用外观模式实现一键看电影功能。
|
||||
|
||||
```java
|
||||
public class SubSystem {
|
||||
@ -2811,7 +2806,7 @@ public class Client {
|
||||
|
||||
### 设计原则
|
||||
|
||||
最少知识原则:只和你的密友谈话。也就是客户对象所需要交互的对象应当尽可能少。
|
||||
最少知识原则:只和你的密友谈话。也就是说客户对象所需要交互的对象应当尽可能少。
|
||||
|
||||
## 6. 享元(Flyweight)
|
||||
|
||||
@ -2822,8 +2817,8 @@ public class Client {
|
||||
### 类图
|
||||
|
||||
- Flyweight:享元对象
|
||||
- IntrinsicState:内部状态,相同的项元对象共享
|
||||
- ExtrinsicState:外部状态
|
||||
- IntrinsicState:内部状态,享元对象共享内部状态
|
||||
- ExtrinsicState:外部状态,每个享元对象的外部状态不同
|
||||
|
||||
<div align="center"> <img src="../pics//d52270b4-9097-4667-9f18-f405fc661c99.png"/> </div><br>
|
||||
|
||||
@ -2854,8 +2849,6 @@ public class ConcreteFlyweight implements Flyweight {
|
||||
```
|
||||
|
||||
```java
|
||||
import java.util.HashMap;
|
||||
|
||||
public class FlyweightFactory {
|
||||
|
||||
private HashMap<String, Flyweight> flyweights = new HashMap<>();
|
||||
|
Reference in New Issue
Block a user