一、单例设计模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1,单例模式的结构
单例模式的主要有以下角色:
单例类。只能创建一个实例的类
访问类。使用单例类
2,单例模式的实现
单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建
懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
2.1,饿汉式
2.1.1,静态变量方式
/*** @Author zhou_ge* @Date 2022/6/23 12:08* @PackageName:xyz.zhouge.designPatterns.singleton.hungry.staticVar* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {//私有构造方法private DataBase(){}//创建静态变量private static DataBase connection = new DataBase();//创建公共的静态获取变量方法public static DataBase getConnection(){return connection;}}
/*** @Author zhou_ge* @Date 2022/6/23 12:12* @PackageName:xyz.zhouge.designPatterns.singleton.hungry.staticVar* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase var1 = DataBase.getConnection();//实例1DataBase var2 = DataBase.getConnection();//实例2System.out.println(var1.equals(var2));}}
2.1.2,静态代码块方式
/*** @Author zhou_ge* @Date 2022/6/23 12:15* @PackageName:xyz.zhouge.designPatterns.singleton.hungry.staticBlock* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {private DataBase(){}private static DataBase connection ;static {connection = new DataBase();}public static DataBase getConnection(){return connection;}}
/*** @Author zhou_ge* @Date 2022/6/23 12:12* @PackageName:xyz.zhouge.designPatterns.singleton.hungry.staticVar* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase var1 = DataBase.getConnection();DataBase var2 = DataBase.getConnection();System.out.println(var1.equals(var2));}}
2.2,懒汉式
2.2.1,线程不安全
/*** @Author zhou_ge* @Date 2022/6/23 12:23* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.safety* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {//1,将构造器私有化private DataBase(){}//2,声明私有化成员变量private static DataBase connection = null;//3,成员方法初始化成员变量public static DataBase getConnection(){//判空if (connection == null){connection = new DataBase();}return connection;}}
/*** @Author zhou_ge* @Date 2022/6/23 12:28* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.safety* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase conn1 = DataBase.getConnection();DataBase conn2 = DataBase.getConnection();System.out.println(conn1.equals(conn2));}}
2.2.2,线程安全(同步锁)
/*** @Author zhou_ge* @Date 2022/6/23 12:30* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.unSafety* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {private DataBase(){}private static DataBase connection ;public synchronized static DataBase getConnection(){if (connection == null){connection = new DataBase();}return connection;}}
/*** @Author zhou_ge* @Date 2022/6/23 12:32* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.safety* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase conn1 = DataBase.getConnection();DataBase conn2 = DataBase.getConnection();System.out.println(conn1.equals(conn2));}}
2.3,双检锁(volatile模式)
/*** @Author zhou_ge* @Date 2022/6/23 14:42* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.doubleLock* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {//private constructorprivate DataBase(){}//member variable ; volatile 保证关键字可以保证可见性和有序性private static volatile DataBase connection ;//public methodpublic static DataBase getConnection(){//validate connectionif (connection == null){//synchronized locksynchronized (DataBase.class){//validate again after getting the lockif (connection == null){connection = new DataBase();}}}return connection;}}
/*** @Author zhou_ge* @Date 2022/6/23 14:48* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.doubleLock* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase conn1 = DataBase.getConnection();DataBase conn2 = DataBase.getConnection();System.out.println(conn1.equals(conn2));}}
2.4,静态内部类
/*** @Author zhou_ge* @Date 2022/6/23 14:53* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.static_inner_class* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {//private constructorprivate DataBase(){}//static inner classprivate static class DataBaseHolder{private static final DataBase CONNECTION = new DataBase();}/*** 静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态* 内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被* static 修饰,保证只被实例化一次,并且严格保证实例化顺序。** 说明:* 第一次加载Singleton类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加* 载SingletonHolder* 并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。**///public methodpublic static DataBase getConnection(){return DataBaseHolder.CONNECTION;}}
/*** @Author zhou_ge* @Date 2022/6/23 14:56* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.static_inner_class* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase conn1 = DataBase.getConnection();DataBase conn2 = DataBase.getConnection();System.out.println(conn1.equals(conn2));}}
2.5,枚举方式
/*** @Author zhou_ge* @Date 2022/6/23 15:00* @PackageName:xyz.zhouge.designPatterns.singleton.enum_* @ClassName: DataBase* @Description: 枚举方式实现* @Version 1.0*/public enum DataBase {Connection;/***枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一* 次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是* 所用单例实现中唯一一种不会被破坏的单例实现模式。*/}
/*** @Author zhou_ge* @Date 2022/6/23 15:00* @PackageName:xyz.zhouge.designPatterns.singleton.enum_* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {DataBase conn1 = DataBase.Connection;DataBase conn2 = DataBase.Connection;System.out.println(conn1.equals(conn2));}}
3,存在的问题
上面定义的单例类(Singleton)可以创建多个对象,枚举方式除外。有两种方式,分别是序列化和反射
3.1,序列化与反序列化
/*** @Author zhou_ge* @Date 2022/6/23 14:53* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.static_inner_class* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase implements Serializable {//private constructorprivate DataBase(){}//static inner classprivate static class DataBaseHolder{private static final DataBase CONNECTION = new DataBase();}/*** 静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态* 内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被* static 修饰,保证只被实例化一次,并且严格保证实例化顺序。** 说明:* 第一次加载Singleton类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加* 载SingletonHolder* 并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。**///public methodpublic static DataBase getConnection(){return DataBaseHolder.CONNECTION;}//解决序列化破坏单例的方案private Object readResolve(){return DataBaseHolder.CONNECTION;}}
/*** @Author zhou_ge* @Date 2022/6/23 14:56* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.static_inner_class* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {//writeObjectToFile();DataBase conn1 = readObjectFromFile();DataBase conn2 = readObjectFromFile();System.out.println(conn1.equals(conn2));}//读取对象,写入文件public static void writeObjectToFile(){try {//1,获取对象DataBase conn = DataBase.getConnection();//2,创建对象输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("H:\\desktop\\a.txt"));//3,将对象写入文件中oos.writeObject(conn);} catch (IOException e) {e.printStackTrace();}}//读取文件,转为对象public static DataBase readObjectFromFile(){DataBase conn = null;try {//1,获取文件ObjectInputStream ois = new ObjectInputStream(new FileInputStream("H:\\desktop\\a.txt"));//2,读取对象conn = (DataBase) ois.readObject();System.out.println(conn);} catch (Exception e) {e.printStackTrace();}finally {return conn;}}}
3.2,反射
/*** @Author zhou_ge* @Date 2022/6/23 14:42* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.doubleLock* @ClassName: DataBase* @Description: TODO* @Version 1.0*/public class DataBase {//private constructorprivate DataBase(){if (connection != null){throw new RuntimeException();}}//member variable ; volatile 保证关键字可以保证可见性和有序性private static volatile DataBase connection ;//public methodpublic static DataBase getConnection(){//validate connectionif (connection != null){return connection;}//synchronized locksynchronized (DataBase.class){//validate again after getting the lockif (connection != null){return connection;}connection = new DataBase();return connection;}}}
/*** @Author zhou_ge* @Date 2022/6/23 14:56* @PackageName:xyz.zhouge.designPatterns.singleton.lazy.static_inner_class* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) {try {//1,获取DataBase的字节码对象Class<DataBase> clazz = DataBase.class;//2,获取无参构造方法Constructor<DataBase> constructor = clazz.getDeclaredConstructor();//3,取消访问权限constructor.setAccessible(true);//4,获取对象DataBase conn1 = constructor.newInstance();DataBase conn2 = constructor.newInstance();System.out.println(conn1.equals(conn2));} catch (Exception e) {e.printStackTrace();}}}
4,Runtime源码解析
/*** @Author zhou_ge* @Date 2022/6/23 16:20* @PackageName:xyz.zhouge.designPatterns.singleton.RuntimeDemo* @ClassName: Test* @Description: TODO* @Version 1.0*/public class Test {public static void main(String[] args) {try {//获取Runtime类对象Runtime runtime = Runtime.getRuntime();//返回 Java 虚拟机中的内存总量。System.out.println(runtime.totalMemory());//返回 Java 虚拟机试图使用的最大内存量。System.out.println(runtime.maxMemory());//创建一个新的进程执行指定的字符串命令,返回进程对象Process process = runtime.exec("ipconfig");//获取命令执行后的结果,通过输入流获取InputStream inputStream = process.getInputStream();byte[] arr = new byte[1024 * 1024 * 100];int b = inputStream.read(arr);System.out.println(new String(arr, 0, b, "gbk"));} catch (Exception e) {e.printStackTrace();}}}
二、工厂模式
三、原型模式
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
1,原型模式的结构
原型模式包含如下角色:
抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
访问类:使用具体原型类中的 clone() 方法来复制新的对象。
2,原型模式的分类
原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
3,浅克隆案例
3.1,案例一
3.1.1,克隆接口(抽象原型类)
/*** @Author zhou_ge* @Date 2022/6/28 12:44* @PackageName:xyz.zhouge.designPatterns.prototype.shallowCloning.abstractObject* @ClassName: Student* @Description: TODO* @Version 1.0*/public abstract class StudentPrototype implements Cloneable{}
3.1.2,具体原型类
/*** @Author zhou_ge* @Date 2022/6/28 12:46* @PackageName:xyz.zhouge.designPatterns.prototype.shallowCloning.specificObject* @ClassName: Student* @Description: TODO* @Version 1.0*/public class Student extends StudentPrototype {public Student() {System.out.println("Student prototype object had created ...");}@Overridepublic Student clone() throws CloneNotSupportedException {System.out.println("Student prototype object had cloned ...");return (Student) super.clone();}}
3.1.3,访问类
/*** @Author zhou_ge* @Date 2022/6/29 14:24* @PackageName:xyz.zhouge.designPatterns.prototype.shallow_clone* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) throws CloneNotSupportedException {Student stu1 = new Student();Student stu2 = stu1.clone();System.out.println(stu1 == stu2);//false ,shallow clone/**** 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。** 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。*/}}
3.2,案例二
3.2.1,克隆接口(抽象原型类)
/*** @Author zhou_ge* @Date 2022/6/29 14:32* @PackageName:xyz.zhouge.designPatterns.prototype.shallow_clone.demo2.abstractObject* @ClassName: CitationPrototype* @Description: TODO* @Version 1.0*/public abstract class CitationPrototype implements Cloneable{}
3.2.2,具体原型类
/*** @Author zhou_ge* @Date 2022/6/29 14:33* @PackageName:xyz.zhouge.designPatterns.prototype.shallow_clone.demo2.specificObject* @ClassName: Citation* @Description: TODO* @Version 1.0*/public class Citation extends CitationPrototype {private String name ;public String getName() {return name;}public void setName(String name) {this.name = name;}public Citation() {System.out.println("Citation object had created ...");}@Overridepublic Citation clone() throws CloneNotSupportedException {System.out.println("Citation object had cloned ...");return (Citation) super.clone();}public void showCitation(){System.out.println(name + " 同学:在2021-2022学年第一学期中表现优秀,特发此状,以资鼓励!");}}
3.2.3,访问类
/*** @Author zhou_ge* @Date 2022/6/29 14:37* @PackageName:xyz.zhouge.designPatterns.prototype.shallow_clone.demo2* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) throws CloneNotSupportedException {//test1();test2();}public static void test1() throws CloneNotSupportedException {//1,create prototype objectCitation c1 = new Citation();c1.setName("zhangSan");//2,clone prototype objectCitation c2 = c1.clone();c2.setName("lisi");c1.showCitation();c2.showCitation();System.out.println(c1 == c2);/**** 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。** 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。*/}public static void test2() throws CloneNotSupportedException {//1,create prototype objectCitation c1 = new Citation();//2,clone prototype objectCitation c2 = c1.clone();//3,set variable valuec1.setName("zhangSan");c2.setName("lisi");c1.showCitation();c2.showCitation();System.out.println(c1 == c2);/**** 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原* 有属性所指向的对象的内存地址。** 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。*/}}
4,深克隆案例
4.1,案例一(浅克隆)
4.1.1,克隆接口(抽象原型类)
/*** @Author zhou_ge* @Date 2022/6/29 14:51* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1.abstractObject* @ClassName: CitationPrototype* @Description: TODO* @Version 1.0*/public abstract class CitationPrototype implements Cloneable{}
4.1.2,具体原型类
/*** @Author zhou_ge* @Date 2022/6/29 14:53* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1.specificObject* @ClassName: Citation* @Description: TODO* @Version 1.0*/public class Citation extends CitationPrototype {private Student stu ;public Student getStu() {return stu;}public void setStu(Student stu) {this.stu = stu;}public void show(){System.out.println(stu.getStuName() + " 同学:在2021-2022学年第一学期中表现优秀,特发此状,以资鼓励!");}@Overridepublic Citation clone() throws CloneNotSupportedException {System.out.println("Citation object had cloned ...");return (Citation) super.clone();}}
/*** @Author zhou_ge* @Date 2022/6/29 14:52* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1.specificObject* @ClassName: Student* @Description: TODO* @Version 1.0*/public class Student {private String stuName ;private String address ;public Student(String stuName, String address) {this.stuName = stuName;this.address = address;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}}
4.1.3,访问类
/*** @Author zhou_ge* @Date 2022/6/29 14:56* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) throws CloneNotSupportedException {//浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性(Student.stuName),仍指向原有属性所指向的对象的内存地址。Student stu1 = new Student("zhangSan", "十堰");Citation c1 = new Citation();c1.setStu(stu1);Citation c2 = c1.clone();Student stu2 = c2.getStu();stu2.setStuName("lisi");//c2对象是从c1克隆过来的,stu2是非基本类型,修改stu2的属性值,也会把stu1的进行修改System.out.println(stu1 == stu2);c1.show();c2.show();/**stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流*/}}
4.2,案例二
4.2.1,原型接口(抽象原型类)
/*** @Author zhou_ge* @Date 2022/6/29 14:51* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1.abstractObject* @ClassName: CitationPrototype* @Description: TODO* @Version 1.0*/public abstract class CitationPrototype implements Cloneable{}
4.2.2,具体原型类
/*** @Author zhou_ge* @Date 2022/6/29 14:53* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo1.specificObject* @ClassName: Citation* @Description: TODO* @Version 1.0*/public class Citation extends CitationPrototype implements Serializable {private Student stu ;public Student getStu() {return stu;}public void setStu(Student stu) {this.stu = stu;}public void show(){System.out.println(stu.getStuName() + " 同学:在2021-2022学年第一学期中表现优秀,特发此状,以资鼓励!");}@Overridepublic Citation clone() throws CloneNotSupportedException {System.out.println("Citation object had cloned ...");return (Citation) super.clone();}}
/*** @Author zhou_ge* @Date 2022/6/29 14:52* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo2.specificObject* @ClassName: Student* @Description: TODO* @Version 1.0*/public class Student implements Serializable {private String stuName ;private String address ;public Student(String stuName, String address) {this.stuName = stuName;this.address = address;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}}
4.2.3,访问类
/*** @Author zhou_ge* @Date 2022/6/29 15:06* @PackageName:xyz.zhouge.designPatterns.prototype.deep_clone.demo2* @ClassName: Client* @Description: TODO* @Version 1.0*/public class Client {public static void main(String[] args) throws Exception {shallow_clone();System.out.println("======================");deep_clone();}public static void shallow_clone() throws Exception {//浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性(Student.stuName),仍指向原有属性所指向的对象的内存地址。Student stu1 = new Student("zhangSana", "十堰");Citation c1 = new Citation();c1.setStu(stu1);Citation c2 = c1.clone();Student stu2 = c2.getStu();stu2.setStuName("lisi");//c2对象是从c1克隆过来的,stu2是非基本类型,修改stu2的属性值,也会把stu1的进行修改System.out.println(stu1 == stu2);c1.show();c2.show();/**stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流*/}public static void deep_clone() throws Exception {//1,创建citaion对象Student stu1 = new Student("zhangSan", "shiyan");Citation c1 = new Citation();c1.setStu(stu1);//2,写入对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("H:\\desktop\\temp.txt"));oos.writeObject(c1);oos.close();//3,读取对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("H:\\desktop\\temp.txt"));Citation c2 = (Citation) ois.readObject();Student stu2 = c2.getStu();stu2.setStuName("lisi");c1.show();c2.show();System.out.println(stu1 == stu2);}}
四、建造者模式
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
-分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况。
-由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
-建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。
1,建造者模式的结构
建造者(Builder)模式包含如下角色:
抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
产品类(Product):要创建的复杂对象。
指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
2,建造者模式案例
【创建共享单车】
生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。
这里Bike是产品,包含车架,车座等组件;Builder是抽象建造,MobikeBuilder和OfoBuilder是具体的建造者;Director是指挥者。




