From 6858a78396a277781e2cf5a1e597d6879242b7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E7=A5=A5?= <1366971433@qq.com> Date: Mon, 2 Dec 2019 17:58:59 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/Java/design-pattern/EnumSingletonFile | Bin 0 -> 109 bytes code/Java/design-pattern/SingletonFile | Bin 0 -> 72 bytes .../simple_factory/PhoneFactory.java | 7 +- .../DoubleCheckLazySingletonSafe.java | 23 + .../creational/singleton/EnumInstance.java | 23 + .../singleton/EnumInstanceTest.java | 21 + .../creational/singleton/HungrySingleton.java | 29 + .../singleton/LazySingletonUnsafe.java | 19 + .../singleton/ReflectionDamage.java | 15 + .../singleton/SerializationDamage.java | 17 + .../StaticInnerClassHungrySingleton.java | 21 + .../creational/singleton/ZTest.java | 10 + notes/Java_设计模式.md | 526 +++++++++++++++++- pictures/23_abstract_factory.png | Bin 0 -> 25689 bytes pictures/23_builder.png | Bin 0 -> 12981 bytes pictures/23_factory_method.png | Bin 0 -> 10659 bytes pictures/23_simple_factory.png | Bin 0 -> 10375 bytes 17 files changed, 694 insertions(+), 17 deletions(-) create mode 100644 code/Java/design-pattern/EnumSingletonFile create mode 100644 code/Java/design-pattern/SingletonFile create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/DoubleCheckLazySingletonSafe.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstance.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstanceTest.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/HungrySingleton.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/LazySingletonUnsafe.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ReflectionDamage.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/SerializationDamage.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/StaticInnerClassHungrySingleton.java create mode 100644 code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ZTest.java create mode 100644 pictures/23_abstract_factory.png create mode 100644 pictures/23_builder.png create mode 100644 pictures/23_factory_method.png create mode 100644 pictures/23_simple_factory.png diff --git a/code/Java/design-pattern/EnumSingletonFile b/code/Java/design-pattern/EnumSingletonFile new file mode 100644 index 0000000000000000000000000000000000000000..a484639df7d9144bef3be145171ab2451b39dea4 GIT binary patch literal 109 zcmZ4UmVvddh`}H^KUXg!H8UwOvobR;T`##PHL)Z!KQA#yuNcVBNiE6G({s%$&GpPH sE=kNwPGx`sAqIwuA_l&!#Ii)aoJ62bkRoKsf)WM}Pru+0M?Ys*0KdE+m;e9( literal 0 HcmV?d00001 diff --git a/code/Java/design-pattern/SingletonFile b/code/Java/design-pattern/SingletonFile new file mode 100644 index 0000000000000000000000000000000000000000..3eb9713da9138f8425edfdb4cc3478164dcf8561 GIT binary patch literal 72 zcmZ4UmVvdnh`~5HKUXg!H8UwOvobR;T`##PHL)Z!KQA#yuNcVBNiE6G)AK0JOE0Pn UhVg}Kz2^j6{e7Q_fuW)R0PzVNOaK4? literal 0 HcmV?d00001 diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/simple_factory/PhoneFactory.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/simple_factory/PhoneFactory.java index a17deb0..bafa319 100644 --- a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/simple_factory/PhoneFactory.java +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/simple_factory/PhoneFactory.java @@ -14,15 +14,10 @@ public class PhoneFactory { public Phone getPhone(Class phoneClass) { try { return (Phone) Class.forName(phoneClass.getName()).newInstance(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return null; } - } diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/DoubleCheckLazySingletonSafe.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/DoubleCheckLazySingletonSafe.java new file mode 100644 index 0000000..d946b41 --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/DoubleCheckLazySingletonSafe.java @@ -0,0 +1,23 @@ +package com.heibaiying.creational.singleton; + +/** + * 使用双重检查锁来保证线程安全 + */ +public class DoubleCheckLazySingletonSafe { + + private static volatile DoubleCheckLazySingletonSafe instance = null; + + private DoubleCheckLazySingletonSafe() { + } + + public static DoubleCheckLazySingletonSafe getInstance() { + if (instance == null) { + synchronized (DoubleCheckLazySingletonSafe.class) { + if (instance == null) { + instance = new DoubleCheckLazySingletonSafe(); + } + } + } + return instance; + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstance.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstance.java new file mode 100644 index 0000000..b023c31 --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstance.java @@ -0,0 +1,23 @@ +package com.heibaiying.creational.singleton; + +/** + * 利用枚举实现单例 + */ +public enum EnumInstance { + + INSTANCE; + + private String field; + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public static EnumInstance getInstance() { + return INSTANCE; + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstanceTest.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstanceTest.java new file mode 100644 index 0000000..601cff1 --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/EnumInstanceTest.java @@ -0,0 +1,21 @@ +package com.heibaiying.creational.singleton; + +import java.io.*; +import java.lang.reflect.Constructor; + +public class EnumInstanceTest { + public static void main(String[] args) throws Exception { + // 序列化攻击 + EnumInstance instance = EnumInstance.getInstance(); + ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("EnumSingletonFile")); + outputStream.writeObject(instance); + ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("EnumSingletonFile"))); + EnumInstance newInstance = (EnumInstance) inputStream.readObject(); + System.out.println(instance == newInstance); + // 反射攻击,Enum类中只有一个两个参数的构造器:Enum(String name, int ordinal) + Constructor constructor = EnumInstance.class.getDeclaredConstructor(String.class, int.class); + constructor.setAccessible(true); + EnumInstance enumInstance = constructor.newInstance("name", 0); + System.out.println(instance == enumInstance); + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/HungrySingleton.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/HungrySingleton.java new file mode 100644 index 0000000..146357c --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/HungrySingleton.java @@ -0,0 +1,29 @@ +package com.heibaiying.creational.singleton; + +import java.io.Serializable; + +/** + * 利用静态代码块来实现饿汉式单例 + */ +public class HungrySingleton implements Serializable { + + private static final HungrySingleton instance; + + static { + instance = new HungrySingleton(); + } + + private HungrySingleton() { + if (instance != null) { + throw new RuntimeException("单例模式禁止反射调用"); + } + } + + public static HungrySingleton getInstance() { + return instance; + } + + private Object readResolve() { + return instance; + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/LazySingletonUnsafe.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/LazySingletonUnsafe.java new file mode 100644 index 0000000..31710bb --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/LazySingletonUnsafe.java @@ -0,0 +1,19 @@ +package com.heibaiying.creational.singleton; + +/** + * 线程不安全的懒汉式单例模式 + */ +public class LazySingletonUnsafe { + + private static LazySingletonUnsafe instance = null; + + private LazySingletonUnsafe() { + } + + public static LazySingletonUnsafe getInstance() { + if (instance == null) { + instance = new LazySingletonUnsafe(); + } + return instance; + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ReflectionDamage.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ReflectionDamage.java new file mode 100644 index 0000000..6e06fed --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ReflectionDamage.java @@ -0,0 +1,15 @@ +package com.heibaiying.creational.singleton; + +import java.lang.reflect.Constructor; + +/** + * 利用反射破坏单例 + */ +public class ReflectionDamage { + public static void main(String[] args) throws Exception { + Constructor constructor = HungrySingleton.class.getDeclaredConstructor(); + constructor.setAccessible(true); + HungrySingleton hungrySingleton = constructor.newInstance(); + System.out.println(hungrySingleton); + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/SerializationDamage.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/SerializationDamage.java new file mode 100644 index 0000000..78af91f --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/SerializationDamage.java @@ -0,0 +1,17 @@ +package com.heibaiying.creational.singleton; + +import java.io.*; + +/** + * 利用序列化破坏单例 + */ +public class SerializationDamage { + public static void main(String[] args) throws IOException, ClassNotFoundException { + HungrySingleton instance = HungrySingleton.getInstance(); + ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("SingletonFile")); + outputStream.writeObject(instance); + ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("SingletonFile"))); + HungrySingleton newInstance = (HungrySingleton) inputStream.readObject(); + System.out.println(instance == newInstance); + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/StaticInnerClassHungrySingleton.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/StaticInnerClassHungrySingleton.java new file mode 100644 index 0000000..eb56612 --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/StaticInnerClassHungrySingleton.java @@ -0,0 +1,21 @@ +package com.heibaiying.creational.singleton; + +/** + * 利用静态内部类来实现饿汉式单例 + */ +public class StaticInnerClassHungrySingleton { + + private static class InnerClass { + private static StaticInnerClassHungrySingleton instance = new StaticInnerClassHungrySingleton(); + } + + public static StaticInnerClassHungrySingleton getInstance() { + return InnerClass.instance; + } + + private StaticInnerClassHungrySingleton() { + if (InnerClass.instance != null) { + throw new RuntimeException("单例模式禁止反射调用"); + } + } +} diff --git a/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ZTest.java b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ZTest.java new file mode 100644 index 0000000..b1e5378 --- /dev/null +++ b/code/Java/design-pattern/src/main/java/com/heibaiying/creational/singleton/ZTest.java @@ -0,0 +1,10 @@ +package com.heibaiying.creational.singleton; + +public class ZTest { + public static void main(String[] args) { + HungrySingleton hungrySingleton = HungrySingleton.getInstance(); + StaticInnerClassHungrySingleton staticInnerClassHungrySingleton = StaticInnerClassHungrySingleton.getInstance(); + DoubleCheckLazySingletonSafe doubleCheckLazySingletonSafe = DoubleCheckLazySingletonSafe.getInstance(); + EnumInstance instance = EnumInstance.getInstance(); + } +} diff --git a/notes/Java_设计模式.md b/notes/Java_设计模式.md index 4f3d5db..526590e 100644 --- a/notes/Java_设计模式.md +++ b/notes/Java_设计模式.md @@ -2,38 +2,542 @@ ## 软件设计的原则 -### 开闭原则 +### 1. 开闭原则 定义:软件实体应当对扩展开放,对修改关闭。 -### 里氏替换原则 +### 2. 里氏替换原则 定义:继承必须保证确保超类所拥有的性质在子类中仍然成立。即子类在继承父类时,除了添加新的方法来新增功能外,尽量避免重写父类方法,因为这会导致整个继承体系的复用性变差。 -### 依赖倒置原则 +### 3. 依赖倒置原则 定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是要面向接口编程,而不是面向实现编程,这样可以降低耦合性,提高系统稳定性,提高代码的可读性和可维护性。 -### 单一职责原则 +### 4. 单一职责原则 -定义:一个类应该有且仅有一个引起它变化的原则,否则应类应该被拆分。其核心思想是控制类的粒度大小、提高类的内聚性。 +定义:一个类应该有且仅有一个引起它变化的原则,否则类应该被拆分。其核心思想是控制类的粒度大小、提高类的内聚性。 -### 接口隔离原则 +### 5. 接口隔离原则 定义:一个类对另一个类的依赖应该建立在最小的接口上。其核心思想是要为每个特定的功能建立对应的接口,而不是在一个接口中试图去包含所有功能,既要保证相对独立,也要避免过多接口所导致的臃肿。 -### 迪米特法则 (最少知道原则) +### 6. 迪米特法则 (最少知道原则) 定义:如果两个软件实体不需要直接通讯,那么就应该避免直接互相调用,而是通过第三方转发该调用,从而降低耦合度,保证模块的相对独立。 -### 合成复用原则 (组合复用原则) +### 7. 合成复用原则 (组合复用原则) 定义:应该优先使用组合、聚合等关联关系来实现复用,其次才是考虑使用继承关系。 -### 总结 +**总结**:开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。 -开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。 +# 创建型 +## 1. 单例模式 +### 1.1 饿汉式单例 -## 二、工厂模式 \ No newline at end of file +饿汉式单例是最简单一种单例模式,它在类初始化时就完成相关单例对象的创建,可以通过静态代码块或静态内部类的方式来进行实现: + +静态代码块方式: + +```java +public class HungrySingleton implements Serializable { + + private static final HungrySingleton instance; + + static { + instance = new HungrySingleton(); + } + + // 确保构造器私有 + private HungrySingleton() {} + + // 获取单例对象 + public static HungrySingleton getInstance() { + return instance; + } +} +``` + +静态内部类方式: + +```java +public class StaticInnerClassHungrySingleton { + + private static class InnerClass { + private static StaticInnerClassHungrySingleton instance = new StaticInnerClassHungrySingleton(); + } + + // 获取单例对象 + public static StaticInnerClassHungrySingleton getInstance() { + return InnerClass.instance; + } + + // 确保构造器私有 + private StaticInnerClassHungrySingleton() { + } +} +``` + +恶汉式单例的优点在于其不存在线程安全问题,对象的唯一性由虚拟机在类初始化创建时保证;其缺点在于如果对象的创建比较消耗资源,并且单例对象不一定会被使用到,此时就会造成资源的浪费。 + +### 1.2 懒汉式单例 + +懒汉式单例的思想在于在需要使用单例对象时再进行创建,如果对象存在则直接返回,如果对象不存在则创建后返回,示例如下: + +```java +public class LazySingletonUnsafe { + + private static LazySingletonUnsafe instance = null; + + private LazySingletonUnsafe() { + } + + public static LazySingletonUnsafe getInstance() { + if (instance == null) { + instance = new LazySingletonUnsafe(); + } + return instance; + } +} +``` + +需要注意的是上面的代码在单线程环境下是没有问题的,但是在多线程环境下是线程不安全的,原因在于下面的创建代码是非原子性的: + +```java +if (instance == null) { + instance = new LazySingletonUnsafe(); +} +``` + +想要保证创建操作的原子性,可以通过 synchronized 关键字来进行实现: + +```java +public synchronized static LazySingletonUnsafe getInstance() { + if (instance == null) { + instance = new LazySingletonUnsafe(); + } + return instance; + } +``` + +此时该方法是线程安全的,但是性能却存在问题。因为 synchronized 修饰的是静态方法,其锁住的是整个类对象,这意味着所有想要获取该单例对象的线程都必须要等待内部锁的释放。假设单例对象已经创建完成,并有 100 个线程并发获取该单例对象,则这 100 个线程都需要等待,显然这会降低系统的吞吐量,因此更好的方式是采用 **双重检查锁的机制** 来实现懒汉式单例: + +```java +public class DoubleCheckLazySingletonSafe { + + // 使用volatile来禁止指令重排序 + private static volatile DoubleCheckLazySingletonSafe instance = null; + + private DoubleCheckLazySingletonSafe() { + } + + public static DoubleCheckLazySingletonSafe getInstance() { + if (instance == null) { + synchronized (DoubleCheckLazySingletonSafe.class) { + if (instance == null) { + instance = new DoubleCheckLazySingletonSafe(); + } + } + } + return instance; + } +} +``` + +还是沿用上面的举例,假设单例对象已经创建完成,并有 100 个线程并发获取该单例对象,此时 `instance == null` 判断肯定是 false,所以所有线程都会直接获得该单例对象,而不会进入 synchronized 同步代码块,这减小了锁的锁定范围,用更小的锁粒度获得了更好的性能。但内部的 `if` 代码块任然需要使用 synchronized 关键字修饰,从而保证整个 if 代码块的原子性。 + +需要注意的是这里的 instance 需要使用 volatile 关键修饰,用于禁止对象在创建过程中出现指令重排序。通常对象的创建分为以下三步: + +1. 给对象分配内存空间; +2. 调用对象的构造器方法,并执行初始化操作; +3. 将变量指向相应的内存地址。 + +如果没有禁止指令重排序,则 2 ,3 步可能会发生指令重排序,这在单线程下是没有问题的,也符合 As-If-Serial 原则,但是如果在多线程下就会出现线程不安全的问题: + +```java +// 2. 由于线程1已经将变量指向内存地址,所以其他线程判断instance不为空,但instance可能尚未初始化完成 +if (instance == null) { + synchronized (DoubleCheckLazySingletonSafe.class) { + if (instance == null) { + // 1. 假设线程1已经给对象分配了内存空间并将变量instance指向了相应的内存地址,但尚未初始化完成 + instance = new DoubleCheckLazySingletonSafe(); + } + } +} +return instance; +``` + +由于重排序的存在,其他线程可能拿到的是一个尚未初始化完成的 instance,此时就可能会导致异常,所以需要禁止其出现指令重排序。 + +### 1.3 使用序列化破坏单例 + +### 1.4 使用反射破坏单例 + +### 1.5 枚举式单例 + +## 2. 简单工厂模式 + +### 2.1 定义 + +对于调用者来说,它无需知道对象的具体创建细节,只需要将自己所需对象的类型告诉工厂,然后由工厂自动创建并返回。 + +### 2.2 实现 + +![23_simple_factory](../pictures/23_simple_factory.png) + +产品抽象类: + +```java +public abstract class Phone { + public abstract void call(String phoneNum); +} +``` + +具体的产品: + +```java +public class HuaweiPhone extends Phone { + public void call(String phoneNum) { + System.out.println("华为手机拨打电话:" + phoneNum); + } +} +``` + +```java +public class XiaomiPhone extends Phone { + public void call(String phoneNum) { + System.out.println("小米手机拨打电话:" + phoneNum); + } +} +``` + +手机工厂: + +```java +public class PhoneFactory { + + public Phone getPhone(String type) { + if ("xiaomi".equalsIgnoreCase(type)) { + return new XiaomiPhone(); + } else if ("huawei".equalsIgnoreCase(type)) { + return new HuaweiPhone(); + } + return null; + } +} +``` + +调用工厂类获取具体的实例: + +```java +public class ZTest { + public static void main(String[] args) { + PhoneFactory phoneFactory = new PhoneFactory(); + phoneFactory.getPhone("xiaomi").call("123"); + phoneFactory.getPhone("huawei").call("321"); + } +} +``` + +### 2.3 缺陷 + +简单工厂的缺陷在于其违背了开闭原则。在简单工厂模式下,如果想要增加新的产品,就需要修改简单工厂中的判断逻辑,这就违背了开闭原则,因此其并不属于 GOF 经典的 23 种设计模式。在 Java 语言中,可以通过泛型来尽量规避这一缺陷,此时需要将创建产品的方法修改为如下所示: + +```java +public Phone getPhone(Class phoneClass) { + try { + return (Phone) Class.forName(phoneClass.getName()).newInstance(); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + e.printStackTrace(); + } + return null; +} +``` + +## 3. 工厂模式 + +### 3.1 定义 + +定义一个用于创建对象的工厂接口,但具体实例化哪一个工厂则由子类来决定。 + +### 3.2 实现 + +![23_factory_method](../pictures/23_factory_method.png) + +产品抽象类: + +```java +public abstract class Phone { + public abstract void call(String phoneNum); +} +``` + +产品实现类: + +```java +public class HuaweiPhone extends Phone { + public void call(String phoneNum) { + System.out.println("华为手机拨打电话:" + phoneNum); + } +} +``` + +```java +public class XiaomiPhone extends Phone { + public void call(String phoneNum) { + System.out.println("小米手机拨打电话:" + phoneNum); + } +} +``` + +工厂接口: + +```java +public interface Factory { + Phone produce(); +} +``` + +工厂实现类: + +```java +public class HuaweiPhoneFactory implements Factory { + @Override + public Phone produce() { + return new HuaweiPhone(); + } +} +``` + +```java +public class XiaomiPhoneFactory implements Factory { + @Override + public Phone produce() { + return new XiaomiPhone(); + } +} +``` + +由调用者来决定实例化哪一个工厂对象: + +```java +public class ZTest { + public static void main(String[] args) { + XiaomiPhoneFactory xiaomiPhoneFactory = new XiaomiPhoneFactory(); + xiaomiPhoneFactory.produce().call("123"); + HuaweiPhoneFactory huaweiPhoneFactory = new HuaweiPhoneFactory(); + huaweiPhoneFactory.produce().call("456"); + } +} +``` + +## 4. 抽象工厂模式 + +### 4.1 定义 + +提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的实现类。 + +### 4.2 实现 + +![23_abstract_factory](../pictures/23_abstract_factory.png) + +假设工厂除了生产手机外,也生产手机的充电器,此时抽象工厂的示例如下: + +充电器抽象类: + +```java +public abstract class Charger { + public abstract void Charge(Phone phone); +} +``` + +充电器实现类: + +```java +public class HuaiweiCharger extends Charger { + @Override + public void Charge(Phone phone) { + System.out.println("华为充电器给" + phone + "充电"); + } +} +``` + +```java +public class XiaomiCharger extends Charger { + @Override + public void Charge(Phone phone) { + System.out.println("小米充电器给" + phone + "充电"); + } +} +``` + +工厂接口: + +```java +public interface Factory { + Phone producePhone(); + Charger produceCharger(); +} +``` + +工厂实现类: + +```java +public class HuaweiPhoneFactory implements Factory { + @Override + public Phone producePhone() { + return new HuaweiPhone(); + } + @Override + public Charger produceCharger() { + return new HuaiweiCharger(); + } +} +``` + +```java +public class XiaomiPhoneFactory implements Factory { + @Override + public Phone producePhone() { + return new XiaomiPhone(); + } + @Override + public Charger produceCharger() { + return new XiaomiCharger(); + } +} +``` + +调用具体的工厂实现类: + +```java +public class ZTest { + public static void main(String[] args) { + XiaomiPhoneFactory xiaomiPhoneFactory = new XiaomiPhoneFactory(); + xiaomiPhoneFactory.produceCharger().Charge(xiaomiPhoneFactory.producePhone()); + HuaweiPhoneFactory huaweiPhoneFactory = new HuaweiPhoneFactory(); + huaweiPhoneFactory.produceCharger().Charge(huaweiPhoneFactory.producePhone()); + } +} +``` + +## 5. 构建者模式 + +### 5.1 定义 + +将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。它是将一个复杂对象的创建过程分解为多个简单的步骤,然后一步一步的组装完成。 + +### 5.2 示例 + +![23_builder](../pictures/23_builder.png) + +产品实体类: + +```java +public class Phone { + /*处理器*/ + private String processor; + /*摄像头*/ + private String camera; + /*屏幕*/ + private String screen; +} +``` + +建造者抽象类: + +```java +public abstract class Builder { + + protected Phone phone = new Phone(); + /*安装处理器*/ + public abstract void addProcessor(); + /*组装摄像头*/ + public abstract void addCamera(); + /*安装屏幕*/ + public abstract void addScreen(); + + public Phone produce() { + return phone; + } +} +``` + +建造者实现类: + +```java +public class HuaweiBuilder extends Builder { + @Override + public void addProcessor() { + phone.setProcessor("海思麒麟处理器"); + } + + @Override + public void addCamera() { + phone.setCamera("莱卡摄像头"); + } + + @Override + public void addScreen() { + phone.setScreen("OLED"); + } +} +``` + +```java +public class XiaomiBuilder extends Builder { + @Override + public void addProcessor() { + phone.setProcessor("高通骁龙处理器"); + } + + @Override + public void addCamera() { + phone.setCamera("索尼摄像头"); + } + + @Override + public void addScreen() { + phone.setScreen("OLED"); + } +} +``` + +定义管理者类: + +```java +public class Manager { + + private Builder builder; + + public Manager(Builder builder) { + this.builder = builder; + } + + public Phone buy() { + builder.addCamera(); + builder.addProcessor(); + builder.addScreen(); + return builder.produce(); + } +} +``` + +调用管理者类获取产品: + +```java +public class ZTest { + public static void main(String[] args) { + Phone huawei = new Manager(new HuaweiBuilder()).buy(); + System.out.println(huawei); + Phone xiaomi = new Manager(new XiaomiBuilder()).buy(); + System.out.println(xiaomi); + } +} +// 输出: +Phone(processor=海思麒麟处理器, camera=莱卡摄像头, screen=OLED) +Phone(processor=高通骁龙处理器, camera=索尼摄像头, screen=OLED) +``` \ No newline at end of file diff --git a/pictures/23_abstract_factory.png b/pictures/23_abstract_factory.png new file mode 100644 index 0000000000000000000000000000000000000000..a9959b92c87492bdaaf560f4ebd50ee762d92903 GIT binary patch literal 25689 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%0A_H+W?+-lZ7w-nDY?eALhNE9?E*By2J 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 XF*VA@qDW#}5E6A|9i?gos}KJL;Wws( literal 0 HcmV?d00001 diff --git a/pictures/23_builder.png b/pictures/23_builder.png new file mode 100644 index 0000000000000000000000000000000000000000..64c065937c3eb510e32e2e2c1ff70e7a7b34e307 GIT binary patch literal 12981 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�n?ZYC{+&t;q>>BU?t!$#B;KF7?v1Ii$*rc1 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 literal 0 HcmV?d00001