1 简介

在最近看的一篇文章中,提到了关于新年目标制定的方式的实践,觉得不错,附在上图。尤其是目标一定要符合SMART模式,

为了…,通过…,截止…前,实现…

这个句式很有力量。
在日常编程实践中,对象的构建和初始化占据着十分重要的作用,在23种设计模式中,如下图所示,关于对象创建的设计模式为创建型设计模式,创建型模式主要用来解决对象的创建问题的。当然,这样的编程实践也和日常生活紧密相关,工厂方法与现实世界中的工厂有着十分相似的现实意义,均用来创建特定类型的东西。对象池模式则可以理解成热水箱和水杯的关系,对象池有缓存的作用,通过水杯,可以使我们一次接水500ml,而减少了去水房的次数,提高了工作效率。

设计模式需要遵循的原则如下所示:

尤其单一职责原则和开闭原则,比较好理解但非常重要。

2 创建型模式理解与实践

创建型模式主要有如下几种设计模式:

在智慧营区中,曾经实践了单例模式和简单工厂模式。

2.1 单例模式

单例模式并不难理解,对于经常操作计算机的我们来说,单例模式有着非常多见的案例,每天在操作电脑时,任务管理器便是单例模式的体现,而Word、Excel这种均为多例实现。而文件资源管理器一次可以打开多个窗口,当然也是不是单例模式的实践。

单例模式的主要特征是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

UML类图如下所示:

2.1.1 实践
在智慧营区项目实践过程中,创建任务时需要首先判断是否具有可用的的服务,而对于不可用服务,使用了单例模式,代码如下所示:

package com.cetc52.camp.domain;import com.cetc52.camp.domain.entity.ServiceEntity;
import com.cetc52.camp.service.InAdequateResourceException;
import com.cetc52.camp.util.HikStatus;/*** 空ServiceEntity实现** @author songquanheng* 2019/10/8-8:28*/
public class NullServiceEntity extends ServiceEntity {@Overridepublic String url() throws InAdequateResourceException {throw new InAdequateResourceException(HikStatus.INADEQUATE_RESOUCE);}private NullServiceEntity() {}private static NullServiceEntity nullServiceEntity;public static synchronized NullServiceEntity nullServiceEntity() {if (nullServiceEntity == null) {nullServiceEntity = new NullServiceEntity();}return nullServiceEntity;}}
2.1.2   枚举实现单例
可以使用闭包和Supplier<T>重新实现单例模式,更为简单,代码如下:
package com.cetc52.camp.common;import java.util.function.Supplier;public enum Singlteton {INSTANCE;public static Supplier<Singlteton> getInstance() {return () -> Singlteton.INSTANCE;}public void doSomething() {System.out.println("Something is done");}
}

客户端可以使用如下代码进行调用:

Singlteton.getInstance().get().doSomething();

2.1.3 Optional empty实例

JDK8为了应对空指针判断而引入了Optional类,Optional本质是一个容器,需要我们将该对象实例传入该容器中。Optional的构造器方法为private,无法直接使用new构建对象,而只能使用Optional提供的静态方法。

package java.util;import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;/*** A container object which may or may not contain a non-{@code null} value.* If a value is present, {@code isPresent()} returns {@code true}. If no* value is present, the object is considered <i>empty</i> and* {@code isPresent()} returns {@code false}.** <p>Additional methods that depend on the presence or absence of a contained* value are provided, such as {@link #orElse(Object) orElse()}* (returns a default value if no value is present) and* {@link #ifPresent(Consumer) ifPresent()} (performs an* action if a value is present).** <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>* class; use of identity-sensitive operations (including reference equality* ({@code ==}), identity hash code, or synchronization) on instances of* {@code Optional} may have unpredictable results and should be avoided.** @apiNote* {@code Optional} is primarily intended for use as a method return type where* there is a clear need to represent "no result," and where using {@code null}* is likely to cause errors. A variable whose type is {@code Optional} should* never itself be {@code null}; it should always point to an {@code Optional}* instance.** @param <T> the type of value* @since 1.8*/
public final class Optional<T> {/*** Common instance for {@code empty()}.*/private static final Optional<?> EMPTY = new Optional<>();/*** If non-null, the value; if null, indicates no value is present*/private final T value;/*** Constructs an empty instance.** @implNote Generally only one empty instance, {@link Optional#EMPTY},* should exist per VM.*/private Optional() {this.value = null;}/*** Returns an empty {@code Optional} instance.  No value is present for this* {@code Optional}.** @apiNote* Though it may be tempting to do so, avoid testing if an object is empty* by comparing with {@code ==} against instances returned by* {@code Optional.empty()}.  There is no guarantee that it is a singleton.* Instead, use {@link #isPresent()}.** @param <T> The type of the non-existent value* @return an empty {@code Optional}*/public static<T> Optional<T> empty() {@SuppressWarnings("unchecked")Optional<T> t = (Optional<T>) EMPTY;return t;}/*** Constructs an instance with the described value.** @param value the non-{@code null} value to describe* @throws NullPointerException if value is {@code null}*/private Optional(T value) {this.value = Objects.requireNonNull(value);}/*** Returns an {@code Optional} describing the given non-{@code null}* value.** @param value the value to describe, which must be non-{@code null}* @param <T> the type of the value* @return an {@code Optional} with the value present* @throws NullPointerException if value is {@code null}*/public static <T> Optional<T> of(T value) {return new Optional<>(value);}/*** Returns an {@code Optional} describing the given value, if* non-{@code null}, otherwise returns an empty {@code Optional}.** @param value the possibly-{@code null} value to describe* @param <T> the type of the value* @return an {@code Optional} with a present value if the specified value*         is non-{@code null}, otherwise an empty {@code Optional}*/public static <T> Optional<T> ofNullable(T value) {return value == null ? empty() : of(value);}/*** If a value is present, returns the value, otherwise throws* {@code NoSuchElementException}.** @apiNote* The preferred alternative to this method is {@link #orElseThrow()}.** @return the non-{@code null} value described by this {@code Optional}* @throws NoSuchElementException if no value is present*/public T get() {if (value == null) {throw new NoSuchElementException("No value present");}return value;}
…
}

而下句代码使用了无锁的线程安全单例模式。
private static final Optional<?> EMPTY = new Optional<>();
Optional类型对象的创建有三种方式

  • Optional.of(obj),如果对象为null,将会抛出NPE。
  • Optional.ofNullable(obj),如果对象为null,将会创建不包含值得empty Optional对象实例
  • Optional.empty()等同于Optional.ofNullable(null)

2.2 工厂模式

首先,可以理解工厂模式在实现世界为什么会存在呢?
我们知道,为了生产一台iphone手机,需要用到很多的模块组件,比如显示屏、按键、wifi模块、蓝牙模块、主板、内存等等,如果真的存在一个Iphone的类型,直接负责来创建(new)相应的实例,太过复杂了。在现实世界基于这样的原因,iphone的设计者以及生产者是分离的,生产的这部分责任交给了工厂,例如富士康。加入工厂这一角色之后,灵活性就随着工厂的功能增加而变得更加丰富。

### 2.2.1 简单工厂模式
工厂模式用于实现逻辑的封装,并通过公共接口提供对象的实例化服务,在增加新的类时只需要做少量的修改。
UML类图如下:

简单工厂方法模式的主要内容如下图所示:

2.2.1.1 实践

/*** 工厂方法模式:由基类统一完成子类对象的生成** @param taskType 任务类型* @return Task task对象*/
public static Task create(String taskType) {assert !GeneralUtil.isInvalid(taskType);switch (taskType) {case FACE_DETECTION:return new FaceDetectionTask();case HUMAN_DETECTION:return new HumanDetectionTask();case HUMAN_ANALYSIS:return new MilitaryAnalysisTask();case HUMAN_DETECTION_ANALYSIS:return new HumanDetectionAnalysisTask();case BEHAVIOR_RECOGNITION:return new BehaviorRecognitionTask();case VEHICLE_ANALYSIS:return new VehicleAnalysisTask();case VIDEO_MOSAIC:return new VideoMosaicTask();case CROWD_DENSITY:return new CrowdDensityTask();case ONE_CLICK:return new OneClickTask();case VIDEO_CONCENTRATION:return new VideoConcentrateTask();case OBJECT_DETECTION:return new ObjectDetectionTask();case GOODS_LEFT:return new GoodsLeftTask();case GOODS_LOSS:return new GoodsLossTask();default:throw new IllegalArgumentException("Incorrect taskType value");}
}

上述工厂类逻辑很简单,只负责Task类的实例化,这是符合单一职责原则的;但是当增加一个新的Task类型时,需要同时对Task类进行修改,这就违反了开闭原则。

2.2.1.2 改进

为了符合开闭原则,可以使用如下的方式进行重构

2.2.1.2.1 反射

需要使用map对象来保存任务ID及其对应的类。

private Map<String, Class> registeredProducts = new HashMap<>();public void registerTask(String taskId, Class taskClass) {registeredProducts.put(taskId, taskClass);
}public Task create(String taskType) throws InstantiationException, IllegalAccessException{Class taskClass = registeredProducts.get(taskType);return (Task)taskClass.newInstance();
}
2.2.1.2.2 newInstance

由于反射需要获取运行时权限,在某些特定的环节下是无法实现的。我们可以不在把特定类型的Class对象放入map中,而把要注册的每种对象实例添加其中。每个产品类都能够创建自己的实例。
实现方式如下:
在Task基类中添加一个抽象方法

public abstract Task newInstance();

然后在工厂类中用map来保存对象的ID及其对应的Task对象。通过实例注册一种新的Task类型。然后稍微修改代码即可达到相应的目的。

2.2.2 工厂方法模式

工厂方法模式是对简单工厂模式的改进。工厂类进行抽象得到工厂类的继承体系,用于实例化特定产品类型的代码被转移到实现抽象方法的子类中。这样不需要修改就可以扩展工厂类(即重新继承抽象工厂接口,生成新的工厂类型)。

工厂方法UML类图如下所示:

虽然手机工厂可以创建手机,但现实世界中会有多个工厂创建不同的产品,类比现实世界,有苹果工厂,华为工厂,三星工厂,因此对工厂类进行抽象封装是完全具有实际意义的。

2.2.3 抽象工厂模式

抽象工厂模式是工厂方法模式的扩展版本,它不再是创建单一类型的对象,而是创建一系列相关的对象。可以这么理解,工厂方法模式中只包含一个抽象产品类,而抽象工厂模式则包含多个抽象产品类型。

一种使用抽象工厂模式的UML类图如下所示:

可以看到在工厂类中同时出现了ICat和IDog两种抽象的产品,这种模式叫做抽象工厂模式。

2.3 建造者模式

当需要实例化一个复杂的类,以得到不同结构和不同内部状态的对象时,我们可以使用不同的类对它们的实例化操作逻辑分别进行封装,这些类就被称为建造者。在JDK中多有类型以Builder结尾,如Lombok中的Builder接口即使用了建造者模式。每当需要来自同一个类但具有不同结构的对象时,就可以通过构造另一个建造者来进行实例化。

2.3.1 参与者

  1. Builder
    为创建一个Product对象的各个部件指定抽象接口。

  2. ConcreteBuilder
    实现Builder的接口以构造和装配该产品的各个部件。
    定义并明确它所创建的表示。
    提供一个检索产品的接口。

  3. Director
    构造一个使用Builder接口的对象。

  4. Product
    表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
    包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

2.3.2 UML类图

2.3.3 主要内容脑图

2.3.4 拥有方法链的匿名建造者

方法链是通过特定方法返回当前对象的一种技术。

builder.setColor("Blue").setEngine("1500cc").addTank("50").addTransmission("auto").build()

2.3.5 Lombock建造者功能

Lombock库将建造者功能作为其功能的一部分。只需要使用@Builder注解,任何类都可以自动或多对建造器方法的访问权限。

Person.builer().name("Adam Savage").city("San Francisco").job("Mythbusters").build()

2.4 原型模式

原型模式即clone模式,实际上只是一种克隆对象的方法。

2.4.1 参与者

  1. Prototype
    声明一个克隆自身的接口。

  2. ConcretePrototype
    实现一个克隆自身的操作。

  3. Client
    让一个原型克隆自身从而创建一个新的对象。

2.5 对象池模式

2.5.1 UML类图

2.5.2 主要内容

3 总结

本文章主要是总结创建型设计模式,这些模式都能够实现新对象的实例化,提高创建对象代码的灵活性和重用性。本文完整的思维导图如下所示:

4 资源下载

设计模式之创建型模式

                             2019-12-14 20:25于浙江图书馆

Java设计模式之创建者模式相关推荐

  1. java设计模式-Builder创建者模式

    问题分析: Builder模式是一步一步创建一个复杂对象的创建型模式.该模式是为了将构建复杂对象的过程和他的部件解耦,使得构建过程和部件的表示隔离开来. Builder模式 主要用于"构建一 ...

  2. JAVA设计模式 - 创建型模式总结

    JAVA设计模式 - 单例模式 JAVA设计模式 - 工厂方法模式 JAVA设计模式 - 抽象工厂模式 JAVA设计模式 - 原型模式 JAVA设计模式 - 建造者模式 1 . 创建型模式的定义 顾名 ...

  3. Java设计模式之 工厂模式(简单工厂模式)

    前一阵子学习了Java 中据说是最简单的设计模式的 单例模式,想一起讨论学习的小伙伴请点击这里: Java 设计模式之单例模式 那么今天就把学习的工厂模式记录下来 工厂模式: 实现了创建者和调用者的分 ...

  4. JAVA设计模式之建造者模式

    转自 JAVA设计模式之建造者模式 建造者模式(Builder)的定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. Builder模式是一步一步创建一个复杂对象的创建型 ...

  5. java备忘录模式应用场景_图解Java设计模式之备忘录模式

    图解Java设计模式之备忘录模式 游戏角色状态恢复问题 游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态. ...

  6. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  7. Java设计模式(访问者模式-迭代器模式-观察者模式-中介者模式)

    Java设计模式Ⅶ 1.访问者模式 1.1 访问者模式概述 1.2 代码理解 2.迭代器模式 2.1 迭代器模式概述 2.2 代码理解 3.观察者模式 3.1 观察者模式概述 3.2 代码理解 4.中 ...

  8. Java设计模式(建造者模式-适配器模式-桥接模式)

    Java设计模式Ⅲ 1.建造者模式 1.1 建造者模式概述 1.2 建造者模式的注意事项和细节 1.3 代码理解 2.适配器模式 2.1 类适配器模式 2.1.1 代码理解 2.2 对象适配器模式 2 ...

  9. Java设计模式(工厂模式>抽象工厂模式和原型模式)

    Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...

最新文章

  1. 试图运行项目时出错,无法启动调试。没有正确安装调试器,请运行安装程序安装或恢复调试器。...
  2. [20180606]如何dump数据库里面的汉字.txt
  3. RMB符号的几种显示方式。
  4. LMS学习函数MATLAB代码
  5. elasticsearch 部署
  6. vb 数组属性_[读书笔记]CSAPP:7[VB]机器级表示:函数
  7. Python3实现文件名排序
  8. maven源码阅读之一(Guice介绍)
  9. Google退出中国的影响分析
  10. 通信技术发展的自然辩证法
  11. UI设计师行业是做什么的?
  12. Android anr模拟,ANR 的模拟
  13. linux图片拼接,如何在Linux上使用Hugin Panorama Creator将照片拼接成全景照片
  14. 基于Ant Design vue框架登录demo
  15. [动态规划] 放置街灯 Uva 10859 - Placing Lampposts
  16. 关于少儿编程编程语言的选择,python还是c++
  17. 什么是迁移学习 (Transfer Learning)?
  18. opencv今犹在,不见当年引路人
  19. java考题_java考题 求助大神
  20. bios 升级后win7无法启动的一个可能原因

热门文章

  1. 解决react脚手架运行后多出来很多webpack的日志
  2. Java中Cookie详解
  3. 方舟上的李德磊--记方舟科技董事长兼总裁李德磊校友
  4. 利用PS快速去除图片中的红章子
  5. “重庆英才·智汇北碚”行动暨产业园成立大会启动
  6. matlab susan,SUSAN算法的matlab代码
  7. php文本书写格式,在PHP中读/写MS Word文件
  8. 推荐系统-模型(一):召回模型【协同过滤类: ItemCF/UserCF】【Embedding类】【Dssm/双塔/word2vec】【图类召回算法 (Deepwalk、EGES)】
  9. excel数据导入python后不对齐_Python处理Excel文件的实用姿势
  10. 学习笔记01-安全术语