先写创建型模式,后续会写结构型模式和行为型模式,分开写主要怕没保存草稿或者误操作.
前言:
1) 设计模式,不是一种语言,也不是什么新api,更不是什么新的语法.
2) 设计模式,是前辈们,不断总结,不断打磨出的设计方法.不同设计模式适用于不同的场景.
3) 设计模式,公认有23种,分别对应23种设计场景.这些设计模式,我们不用怀疑他的功能!
因为这些设计模式是经过长期实践考验而留存下来的.
4) 千万不要以为有任何一种设计模式,他能解决任何问题,每一种设计模式只能用于适合的场景,而不
是万能的.
5) 设计模式有优点,也有缺点.我们不要为了使用设计模式而使用设计模式.切记防止"模式滥用".
6) 23种设计模式,背后其实是7大设计原则.也就是说,每种设计模式都归属于一个或者多个设计原则.
在了解设计模式之前,我们首先要了解七大设计原则,这里不做过多叙述.理解即可.
设计模式推演过程不做展示,只保存完整设计模式代码,供后续场景参考,全是干货.
设计模式分类:
/*设计模式业界公认的有23种分为三种类型
1.创建型模式:单例模式,抽象工厂模式,原型模式,建造者模式,工厂模式
2.结构型模式:适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式
3.行为型模式:模板方法模式,命令模式,访问者模式,迭代器模式,观察者模式,中介者模式,备忘录模式,
解释器模式(intepreter模式),状态模式,策略模式,职责链模式(责任链模式)
*/
七大设计原则:
/*七大设计原则
1.单一职责:每个方法,每个类,每个框架都只做一个事
2.开闭原则:对扩展开放,对修改关闭
3.接口隔离原则:一个接口只有一套增删改查,如果有多种类型的,请写多个接口
4.依赖倒置原则:上层不依赖于下层,他们都应该依赖于抽象,上层值调用方,下层指被调用方
5.迪米特法则(最少知道原则):一个类对于其他类知道的越少越好.只和朋友通信.朋友指:
类中字段,方法的参数,方法的返回值,方法中实例化出来的对象.
6.里氏替换原则:任何能使用父类对象的地方,都能透明的替换成其子类
7.组合/聚合复用原则(组合优于继承原则):尽量使用组合/聚合,尽量不使用类的继承
*/
下面先介绍创建型模式
单例模式:
/*单例模式:在一定的方法中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法).
比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建Session
对象.SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个
SessionFactory就够,这时就会使用到单例模式.
单例模式有8种分别为:
1)饿汉式(静态常量)
2)饿汉式(静态代码块)
3)懒汉式(线程不安全)
4)懒汉式(线程安全,同步方法)
5)懒汉式(线程安全,同步代码块)
6)双检索模式(双重检查模式)
7)静态内部类
8)枚举
*/
/*单例模式使用场景:
1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需
要频繁创建销毁的对象,使用单例模式可以提高系统性能
2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使
用new
3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或
耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数
据库或文件的对象(比如数据源、session工厂等)*/
1.饿汉式-静态常量(不推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//饿汉式(静态常量)
public class SingleTon01 {
//私有化构造器,防止直接new对象
private SingleTon01() {
}
//创建一个静态的对象实例
private static SingleTon01 instance = new SingleTon01();
//提供一个public静态方法,可以返回实例
public static SingleTon01 getInstance(){
return instance;
}
/* 优缺点说明:
1) 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同
步问题。
2) 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始
至终从未使用过这个实例,则会造成内存的浪费
3) 这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载
时就实例化,在单例模式中大多数都是调用getInstance方法, 但是导致类装载
的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类
装载,这时候初始化instance就没有达到lazy loading的效果
4) 结论:这种单例模式可用,可能造成内存浪费*/
public static void main(String[] args) {
SingleTon01 instance = getInstance();
SingleTon01 instance1 = getInstance();
//判断内存地址是否相等
System.out.println(instance == instance1);
//判断哈希code是否相等
System.out.println(instance.hashCode());
System.out.print(instance1.hashCode());
//源码分析:在jdk中runtime就是单例模式(经典的饿汉式)
Runtime runtime = Runtime.getRuntime();
}
}
2.饿汉式-静态代码块(不推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//饿汉式(静态代码块)
public class SingleTon02 {
private static SingleTon02 instance;
//在静态代码块执行时,创建单例对象
static {
instance = new SingleTon02();
}
private SingleTon02(){}
public static SingleTon02 getInstance(){
return instance;
}
// 优缺点说明:
// 1) 这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块
// 中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优
// 缺点和上面是一样的。
// 2) 结论:这种单例模式可用,但是可能造成内存浪费
}
3.懒汉式-线程不安全(不推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//懒汉式(线程不安全)
public class SingleTon03 {
private static SingleTon03 singleTon;
private SingleTon03(){}
//当调用getInstance 才创建单例对象,懒汉式
public static SingleTon03 getInstance(){
if (singleTon == null){
singleTon = new SingleTon03();
}
return singleTon;
}
/* 优缺点说明:
1) 起到了Lazy Loading的效果,但是只能在单线程下使用。
2) 如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及
往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以
在多线程环境下不可使用这种方式
3) 结论:在实际开发中,不要使用这种方式.*/
}
4.懒汉式-线程安全(不推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//懒汉式(线程安全,同步方法)
public class SingleTon04 {
private static SingleTon04 singleTon04;
private SingleTon04(){
}
//加入了同步代码,解决线程不安全问题
public static synchronized SingleTon04 getInstance(){
if (singleTon04 == null){
singleTon04 = new SingleTon04();
}
return singleTon04;
}
/* 优缺点说明:
1) 解决了线程不安全问题
2) 效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行
同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,
直接return就行了。方法进行同步效率太低
3) 结论:在实际开发中,不推荐使用这种方式*/
}
5.懒汉式-线程安全(不推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//懒汉式(线程安全,同步代码块)
public class SingleTon05 {
private static SingleTon05 singleTon05;
private SingleTon05() {
}
public static SingleTon05 getInstance(){
if (singleTon05 == null){
synchronized (SingleTon05.class){
singleTon05 = new SingleTon05();
}
}
return singleTon05;
}
/* 优缺点说明:
1) 这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低,
改为同步产生实例化的的代码块
2) 但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一
致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,
另一个线程也通过了这个判断语句,这时便会产生多个实例
3) 结论:在实际开发中,不能使用这种方式*/
}
6.双检锁式(推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//双检锁模式(双重检查模式)
public class SingleTon06 {
private static volatile SingleTon06 singleTon06;
private SingleTon06() {
}
public static SingleTon06 getInstance(){
if (singleTon06 == null){
synchronized (SingleTon06.class){
if (singleTon06 == null){
singleTon06 = new SingleTon06();
}
}
}
return singleTon06;
}
/* 优缺点说明:
1) Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两
次if (singleton == null)检查,这样就可以保证线程安全了。
2) 这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),
直接return实例化对象,也避免的反复进行方法同步.
3) 线程安全;延迟加载;效率较高
4) 结论:在实际开发中,推荐使用这种单例设计模式*/
}
7.静态内部类(推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//静态内部类
public class SingleTon07 {
private SingleTon07() {
}
//在SingleTon07类装载的时候SingletonInstance静态内部类不会装载,类装载的时候没有线程安全问题
private static class SingletonInstance{
private static final SingleTon07 INSTANCE = new SingleTon07();
}
public static SingleTon07 getInstance(){
return SingletonInstance.INSTANCE;
}
/* 优缺点说明:
1) 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2) 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化
时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的
实例化。
3) 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们
保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
4) 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
5) 结论:推荐使用.*/
}
8.枚举(推举)
package com.hjm.shd.shardingspheredemo.designPatterns.design1;
//枚举
public class SingleTon08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance1 = Singleton.INSTANCE;
System.out.println(instance == instance1);
instance.sayOK();
}
enum Singleton{
INSTANCE;
public void sayOK(){
System.out.println("ok");
}
}
/* 优缺点说明:
1) 这借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而
且还能防止反序列化重新创建新的对象。
2) 这种方式是Effective Java作者Josh Bloch 提倡的方式
3) 结论:推荐使用*/
}
工厂模式:
1.简单工厂模式:
简单工厂模式又叫静态工厂模式,是由一个工厂对象决定创建出那种产品类的实例.
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为
使用场景:在软件开发中,当我们会用到大量创建某种、某类或者某批对象时,就会用到工厂模式.
简单工厂模式适用于具体产品不多,且产品不经常变化的场景,如果具体产品很多,会导致产品工厂臃肿,耦合度高,判断过多.
简单工厂代码如下:
package com.hjm.shd.shardingspheredemo.designPatterns.design2;
//抽象产品
interface Food{
void eat();
}
//具体产品
class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡");
}
}
//具体产品
class RiceNoodle implements Food {
@Override
public void eat() {
System.out.println("吃米线");
}
}
//工厂
class FoodFactory{
public static Food getFood(int n){
Food food = null;
switch (n){
case 1:
food = new Hamburger();
break;
case 2:
food = new RiceNoodle();
break;
}
return food;
}
}
//简单工厂模式
//简单工厂模式适用于,具体产品不多,且产品不经常变化的场景,如果具体产品很多,会导致工厂很臃肿
public class SimpleFactory {
public static void main(String[] args) {
Food food = FoodFactory.getFood(2);
food.eat();
}
}
简单工厂缺点:
当变化来了,客户端需要扩展具体产品的时候,势必需要修改简单工厂中的代码,这样违反了"开闭原则"
2.工厂方法模式
工厂方法模式:定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象实例化推迟到子类中.
工厂方法代码如下:
package com.hjm.shd.shardingspheredemo.designPatterns.design2;
//抽象产品
interface Food{
void eat();
}
//具体产品
class Hamburger3 implements Food{
@Override
public void eat() {
System.out.println("吃汉堡");
}
}
//具体产品
class RiceNoodle implements Food{
@Override
public void eat() {
System.out.println("吃米线");
}
}
//抽象工厂
interface FoodFactory{
public Food getFood();
}
//具体工厂
class HamburgerFactory implements FoodFactory{
@Override
public Food getFood() {
return new Hamburger3();
}
}
class RiceNoodleFactory implements FoodFactory{
@Override
public Food getFood() {
return new RiceNoodle();
}
}
//定义一个品尝的方法
class Bussiness{
public static void taste(FoodFactory foodFactory){
Food food = foodFactory.getFood();
food.eat();
}
}
public class FactoryMethod {
//测试
public static void main(String[] args) {
Bussiness.taste(new HamburgerFactory());
Bussiness.taste(new RiceNoodleFactory());
}
}
工厂方法模式缺点:
虽然此种方法解决了简单工厂,每次扩展都需要修改工厂的问题,但是如果业务种类过多,会产生大量的工厂,不利于后续维护.同时如果工厂的名字进行了修改,客户端还需要跟着修改(工厂的名字修改的概率毕竟小于产品名修改的概率).
3.抽象工厂模式
抽象工厂模式:将简单工厂和工厂方法结合,将工厂抽象为一个(可以有多个抽象方法),解决工厂方法在有多个产品簇时工厂过多问题.比如(食品,饮料,甜品等等)
抽象工厂代码:
package com.hjm.shd.shardingspheredemo.designPatterns.design2;
//抽象工厂
interface Factory{
public Food getFood();
public Drink getDrink();
}
//抽象产品
interface Food{
void eat();
}
interface Drink{
void drink();
}
//具体产品
class Hamburger implements Food{
@Override
public void eat() {
System.out.println("吃汉堡");
}
}
//具体产品
class RiceNoodle implements Food{
@Override
public void eat() {
System.out.println("吃米线");
}
}
class Cola implements Drink{
@Override
public void drink() {
System.out.println("喝可乐");
}
}
class Sprite implements Drink{
@Override
public void drink() {
System.out.println("喝雪碧");
}
}
//具体工厂
class KFCFactory implements Factory{
@Override
public Food getFood() {
return new Hamburger();
}
@Override
public Drink getDrink() {
return new Cola();
}
}
class MDLFactory implements Factory{
@Override
public Food getFood() {
return new RiceNoodle();
}
@Override
public Drink getDrink() {
return new Sprite();
}
}
//定义一个品尝的方法
class Bussiness{
public static void taste(Factory factory){
Food food = factory.getFood();
food.eat();
Drink drink = factory.getDrink();
drink.drink();
}
}
public class abstractFactory {
public static void main(String[] args) {
Bussiness.taste(new KFCFactory());
Bussiness.taste(new MDLFactory());
}
}
抽象工厂缺点:
当产品等级发生变化时(增加产品等级或者删除产品等级),都要引起所有以前工厂代码的修改.违反了开闭原则.
注意:不同老师讲解的抽象工厂与工厂方法略有不同,这里采取其中一种老师的讲法,有的老师在工厂方法讲解时,采用继承抽象类,抽象类的名称不叫xxxfactory(但做的确实是工厂的事情),在讲解抽象工厂的时候采用实现抽象接口(接口名称叫xxxfactory)
此处附上另一种讲解方法图:
产品等级含义:
工厂模式总结:
如果产品等级固定,可以使用抽象工厂
如果产品经常扩展 ,可以使用工厂方法
如果产品不扩充,简单工厂最好
在创建对象实例时,不要直接new出来,而是把new的动作放到工厂中,不要让类继承具体类,而是继承抽象类或者实现接口.
工厂模式在JDK中的应用:
在jdk Calendar中使用了简单工厂模式(静态工厂)如图:
原型模式:
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象.
使用场景:
1.克隆羊问题,通过一只羊克隆出其他羊
2.oa系统中周报模版,员工需要写本周内容,以及下周计划,大部分都不变,只变一小部分,员工可以保存上周模版,下周只修改一小部分.
3.同赛道产品迭代开发,大部分都相同,只有小部分不同(特殊处理)
浅拷贝:对与数据类型是基本数据类型的成员变量,浅拷贝会直接进行传递,也就是把该属性的值复制一份给新对象,对于数据类型是引用数据类型的成员变量,只是把原内容的内存地址给了新对象(拷贝后内存地址一致,修改一个会影响另一个).
深拷贝:复制对象的所有基本数据类型的成员变量值,为所有的引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量(修改克隆后的不会影响原来的).
深拷贝的实现方式有两种:
1.重写clone方法
2.实现序列化接口
原型模式代码:
package com.hjm.shd.shardingspheredemo.designPatterns.design3;
import java.io.Serializable;
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
//构造器
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.hjm.shd.shardingspheredemo.designPatterns.design3;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepProtoType implements Serializable, Cloneable{
public String name; //String 属性
public DeepCloneableTarget deepCloneableTarget;// 引用类型
public DeepProtoType() {
super();
}
//深拷贝 - 方式 1 使用clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//这里完成对基本数据类型(属性)和String的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType)deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone();
return deepProtoType;
}
//深拷贝 - 方式2 通过对象的序列化实现 (推荐)
//先写入内存,在从内存读出来
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType)ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
package com.hjm.shd.shardingspheredemo.designPatterns.design3;
public class Client {
public static void main(String[] args) throws Exception {
DeepProtoType p = new DeepProtoType();
p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
//方式1 完成深拷贝
// DeepProtoType p2 = (DeepProtoType) p.clone();
//
// System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
// System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
//方式2 完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();
System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
}
}
原型模式在spring中的应用:
<!-- 这里我们的 scope="prototype" 即 原型模式来创建 -->
<bean id="id01" class="com.atguigu.spring.bean.Monster" scope="prototype"/>
原型模式的缺点:
需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了开闭(ocp)原则
建造者模式:
建造者模式:又叫生成器模式,是一种对象构建模式,它可以将复杂对象的建造过程抽象查出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现对象.
使用场景:
适用于大部分流程都是不变的,只需要添加修饰的场景
1.盖房子,大部分步骤都固定,例如:打桩、砌墙、封顶.
2.组装电脑,例如:组装cpu、组装gpu、组装内存、组装固态.
建造者模式的四个角色:
1.product(产品角色):一个具体的产品对象
2.builder(抽象建造者):建造一个产品的抽象步骤,通常为接口或者抽象类,需要有一个返回产品的方法
3.concreteBuilder(具体建造者):实现接口,构建和装配各个部件,组合产品对象.
4.Director(指挥者):构建一个使用builder接口的对象,它主要用于创建一个复杂的对象.它主要是用于创建一个复杂的对象.它的作用有两个:一是:隔离客户与对象的产生过程,二是:负责控制产品对象的生产过程.
建造者模式代码:
package com.hjm.shd.shardingspheredemo.designPatterns.design4;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
//电脑类
class Computer{
private String cpu;
private String gpu;
private String memery;
private String hd;
}
//电脑组装者
interface ComputerBuilder{
void setCpu();
void setGpu();
void setMemery();
void setHd();
Computer build();
}
//组装高配版电脑
class AdvancedComputerBuilder implements ComputerBuilder{
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("i7");
}
@Override
public void setGpu() {
computer.setGpu("256G");
}
@Override
public void setMemery() {
computer.setMemery("1T");
}
@Override
public void setHd() {
computer.setHd("成功");
}
@Override
public Computer build() {
return computer;
}
}
//组装低配版电脑
class LowComputerBuilder implements ComputerBuilder{
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("i5");
}
@Override
public void setGpu() {
computer.setGpu("128G");
}
@Override
public void setMemery() {
computer.setMemery("0.5T");
}
@Override
public void setHd() {
computer.setHd("成功2");
}
@Override
public Computer build() {
return computer;
}
}
//指挥者
class Director{
public Computer build(ComputerBuilder cb){
cb.setCpu();
cb.setGpu();
cb.setMemery();
cb.setHd();
return cb.build();
}
}
//客户端测试
public class Test1 {
public static void main(String[] args) {
AdvancedComputerBuilder acb = new AdvancedComputerBuilder();
LowComputerBuilder lcb = new LowComputerBuilder();
Director director = new Director();
//高配
Computer c = director.build(acb);
System.out.println(c);
//低配
Computer c2 = director.build(lcb);
System.out.println(c2);
}
}
建造者模式的优点:
1.创建对象的过程是稳定不变的(因为有ComputerBuilder接口来稳定过程)
2.创建对象的过程只写了一次,没有重复代码(指挥者完成)
3.当需要扩展指挥者的时候,不用修改之前的代码,符合开闭原则
建造者模式和工厂模式的区别:
工厂模式只需要new一个产品即可,建造者模式更注重在new出产品后的,为产品属性赋值的过程.
建造者模式在JDK中的应用:
在StringBuilder源码中:
Appendable接口定义了多个append方法(抽象方法),即Appendable为抽象建造者,定义了抽象方法.
AbstractStringBuilder实现了Appendable接口方法,这里的AbstractStringBuilder已经是建造者,只是不能实例化
StringBuilder即充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由AbstractStringBuilder完成,而StringBuilder继承了AbstractStringBuilder.
至此,23中设计模式中创建型模型全部已经整理完毕,接下来整理结构型模型,最后整理行为型模型.