单例模型
饿汉式
静态方法创建对象
public class Singleton {
// 私有构造方法
private Singleton(){}
private static Singleton instance = new Singleton();
// 提供一个外界获取的方法
public static Singleton getInstance(){
return instance;
}
}
静态代码块创建对象
public class Singleton {
private Singleton(){}
private static Singleton instance;
static {
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
懒汉式
synchronized关键字
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
【
问题
】上边的代码是存在线程不安全的情况的,当线程1进来,判读instance==null成立,准备创建对象;但是线程1还没创建对象完毕时,线程2来了,线程2也判断成立,也去创建对象,此时就会创建两个不同的对象。
【解决
】:给getInstance方法上添加synchronized关键字
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton(); // 下边简称:“写操作”
}
return instance; // 下边简称:“读操作”
}
}
双重检查锁
【问题
】:对于getInstance()方法,其实大部分的操作都是读操作,读操作是线程安全的,如果直接给getInstance方法上加锁,其实会造成大量的线程等待。
【解决
】:调整加锁的时机,双重检查锁
public class Singleton {
private Singleton(){}
private static volatile Singleton instance; // volatile:保证指令的有序性和可见性
public static Singleton getInstance(){
// 第一次判断,如果instance的值不为null,不需要抢占锁,直接返回对象
if(instance == null){
synchronized (Singleton.class){
// 第二次判断
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类
public class Singleton {
private Singleton(){}
// 定义一个静态内部类
private static class SingletonHolder{
// 在内部类中声明并初始化外部类的对象
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
JVM加载外部类的过程是不会加载静态内部类的,只有内部类的属性、方法被调用时才会加载并初始化静态属性。静态属性被static修饰,所以只会被实例化一次。
枚举类
枚举类也是线程安全的,只会被加载一次,也是所有单例实现中唯一一种不会被破坏的单例模式
public enum Singleton {
INSTANCE
}
枚举方式是属于饿汉式的方式,在不考虑浪费内存空间的情况下,首选枚举方式
存在的问题
【问题
】:破坏单例模式(让单例模式可以创建多个对象,枚举方式除外)
通过序列化和反序列化破坏单例模式
public class Client {
public static void main(String[] args) throws Exception {
writeObject2File();
readObjectFromFile(); // Singleton@27bc2616
readObjectFromFile(); // Singleton@3941a79c
}
// 从文件中读取对象
private static void readObjectFromFile() throws Exception {
// 1. 创建输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Desktop\\a.txt"));
// 2. 读取对象
Singleton instance = (Singleton) ois.readObject();
System.out.println(instance);
// 3. 释放资源
ois.close();
}
// 从文件中写对象
public static void writeObject2File() throws Exception {
// 1. 获取Singleton对象
Singleton instance = Singleton.getInstance();
// 2. 将对象写入文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Desktop\\a.txt"));
oos.writeObject(instance);
// 3. 释放资源
oos.close();
}
}
上面的代码生成的两个对象不是同一个对象,破坏了单例模式
通过反射破坏单例模式
public class Client {
public static void main(String[] args) throws Exception {
// 1. 获取Singleton的字节码对象
Class clazz = Singleton.class;
// 2. 获取无参构造方法对象
Constructor cons = clazz.getDeclaredConstructor();
// 3. 取消访问检查(暴力反射)
cons.setAccessible(true);
// 4. 创建对象
Singleton s1 = (Singleton) cons.newInstance();
Singleton s2 = (Singleton) cons.newInstance();
System.out.println(s1 == s2); // false - 破坏单例模式
}
}
上边代码返回的是false,说明s1和s2不是同一个对象,破坏了单例模式
问题解决
序列化、反序列化破坏单例模式解决方法
在Singleton类种添加readResolve()方法,在反序列化时被反射调用。如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回new出来的对象。
public class Singleton implements Serializable {
private Singleton(){}
// 定义一个静态内部类
private static class SingletonHolder{
// 在内部类中声明并初始化外部类的对象
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
// 当进行反序列化时,自动调用该方法,将该方法的返回值直接返回
public Object readResolve(){
return SingletonHolder.INSTANCE;
}
}
反射方式破坏单例模式解决方法
其实反射破坏的原理是:通过反射获取Singleton的私有构造方法,然后通过这个私有的构造方法去创建对象。
因此我们只需要在构造方法里添加一个判断即可
public class Singleton implements Serializable {
private static boolean flag = false;
private Singleton(){
synchronized (Singleton.class){
if(flag) {
throw new RuntimeException("不能创建多个对象");
}
flag = true;
}
}
// 定义一个静态内部类
private static class SingletonHolder{
// 在内部类中声明并初始化外部类的对象
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
JDK源码解析 - Runtime类
饿汉式:
工厂模式
引例:点咖啡
现在有美式咖啡、拿铁咖啡,顾客可以选择咖啡的种类,咖啡都需要进行加糖加奶。
原本的写法:
咖啡类:
public abstract class Coffee {
public abstract String getName();
// 加糖
public void addsugar() {
System.out.println("加糖");
}
// 加奶
public void addmilk() {
System.out.println("加奶");
}
}
美式咖啡:
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
拿铁咖啡:
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "拿铁咖啡";
}
}
咖啡店:
public class CoffeeStore {
public Coffee orderCoffee(String coffeeType) {
// 声明Coffee类型的变量,根据不同的类型创建不同的子类对象
Coffee coffee = null;
if("american".equals(coffeeType)) {
coffee = new AmericanCoffee();
}else if("latte".equals(coffeeType)) {
coffee = new LatteCoffee();
}else {
throw new RuntimeException("对不起的,您所点的咖啡没有");
}
// 加配料
coffee.addmilk();
coffee.addsugar();
return coffee;
}
}
测试方法:
public class Client {
public static void main(String[] args) {
// 创建咖啡店类
CoffeeStore store = new CoffeeStore();
// 点咖啡
Coffee coffee = store.orderCoffee("latte");
System.out.println(coffee.getName());
}
}
【存在问题
】:如果需要更换对象,那么所有new对象的地方都要修改一遍,这就违背了软件设计的开闭原则。
【解决
】:工厂模式
简单工厂模式
角色:
- 抽象产品:定义了产品的规范(咖啡类)
- 具体产品:是现货集成抽象产品的子类(美式咖啡、拿铁咖啡)
- 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品
简单咖啡工厂类,用来生产咖啡:
public class SimpleCoffeeFactory {
public Coffee createCoffee(String coffeeType) {
// 声明Coffee类型的变量,根据不同的类型创建不同的子类对象
Coffee coffee = null;
if("american".equals(coffeeType)) {
coffee = new AmericanCoffee();
}else if("latte".equals(coffeeType)) {
coffee = new LatteCoffee();
}else {
throw new RuntimeException("对不起的,您所点的咖啡没有");
}
return coffee;
}
}
咖啡店:
public class CoffeeStore {
public Coffee orderCoffee(String coffeeType) {
SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
// 调用生产咖啡的方法
Coffee coffee = factory.createCoffee(coffeeType);
// 加配料
coffee.addmilk();
coffee.addsugar();
return coffee;
}
}
解除了CoffeeStore和具体的咖啡的耦合
【优势
】:工厂类的客户端可能有很多,这样只需要去修改SimpleCoffeeFactory的代码,可以省去其他的修改操作。
【劣势
】:如果要再加新的品种的咖啡,就必须要修改SimpleCoffeeFactory的代码,这违反了开闭原则。
工厂方法模式
角色:
- 抽象产品:定义了产品的规范(咖啡类)
- 具体产品:是现货集成抽象产品的子类(美式咖啡、拿铁咖啡)
- 抽象工厂:提供创建产品的接口,调用者通过访问它具体工厂的工厂方法来创建产品
- 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品
抽象工厂:
public interface CoffeeFactory {
// 创建咖啡对象的方法
Coffee createCoffee();
}
具体工厂:
- 拿铁咖啡工厂对象 - 用来生产拿铁咖啡
public class LatteCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
- 美式咖啡工厂对象 - 用来生产美式咖啡
public class AmericanCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
咖啡店:
public class CoffeeStore {
private CoffeeFactory factory;
public void setFactory(CoffeeFactory factory) {
this.factory = factory;
}
// 点咖啡
public Coffee orderCoffee() {
// 创建咖啡
Coffee coffee = factory.createCoffee();
// 加配料
coffee.addmilk();
coffee.addmilk();
return coffee;
}
}
测试方法:
public class Client {
public static void main(String[] args) {
// 创建咖啡店类
CoffeeStore store = new CoffeeStore();
store.setFactory(new AmericanCoffeeFactory()); // 生产美式咖啡
// 点咖啡
Coffee coffee = store.orderCoffee();
System.out.println(coffee.getName());
}
}
【
优势
】:用户只要知道具体工程的类名就可以得到产品;系统增加新的产品只需要新增具体产品类和对应的具体工厂类即可。
【劣势
】:每增加一个产品就需要增加一个具体产品类和具体工厂类, 增加了系统的复杂度
抽象工厂模式
抽象工厂模式和工厂方法模式的区别:
- 工厂方法模式:只生产一个等级的产品
- 抽象工厂模式:可以创建多个不同等级的产品
【需求变更
】:现在咖啡店不仅需要生产咖啡,还需要生产甜品
甜品抽象类:
public abstract class Dessert {
abstract void show();
}
提拉米苏类:
public class Trimisu extends Dessert{
@Override
void show() {
System.out.println("提拉米苏");
}
}
抹茶慕斯类:
public class MatchaMousse extends Dessert{
@Override
void show() {
System.out.println("抹茶慕斯");
}
}
甜品抽象工厂:
public interface DessertFactory {
// 生产咖啡的功能
Coffee createCoffee();
// 生产甜品的功能
Dessert createDessert();
}
意大利风味甜品工厂(生产拿铁咖啡和提拉米苏甜品):
public class ItaltyDessertFactory implements DessertFactory{ // 意大利风味甜品工厂(生产拿铁咖啡和提拉米苏甜品)
@Override
public Coffee createCoffee() {
return new LatteCoffee(); // 拿铁咖啡
}
@Override
public Dessert createDessert() {
return new Trimisu(); // 提拉米苏
}
}
美式咖啡的甜品工厂(生产美式咖啡和抹茶慕斯):
public class AmericanDessertFactory implements DessertFactory{ // 美式咖啡的甜品工厂 - 生产美式咖啡和抹茶慕斯
@Override
public Coffee createCoffee() {
return new AmericanCoffee(); // 美式咖啡
}
@Override
public Dessert createDessert() {
return new MatchaMousse(); // 抹茶慕斯
}
}
测试类:
public class Client {
public static void main(String[] args) {
// 创建意大利风味的工厂
ItaltyDessertFactory it = new ItaltyDessertFactory();
Coffee coffee = it.createCoffee(); // 拿铁咖啡
Dessert dessert = it.createDessert(); // 提拉米苏
System.out.println(coffee.getName());
dessert.show();
}
}
如果要加一个产品族,只需要再加一个对应的工厂类,不需要修改其他类
【优点
】:客户端只能使用同一个产品族中的对象
【缺点
】:产品族种需要新增一个新的产品,所有的工厂类都需要进行修改。
适用场景:
- 需要创建的对象是一系列相互关联或相互依赖的产品族(电器工厂中的电视机、洗衣机、空调)
- 系统种有多个产品族每次只用其中一种产品(有人只喜欢穿一个品牌的衣服和裤子)
- 系统提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构
- 如:搜狗输入法换皮肤(一套一起换)
模式扩展(Spring框架底层)
bean.properties文件:
american = com.itheima.pattern02factory.factory_04_config.AmericanCoffee
latte = com.itheima.pattern02factory.factory_04_config.LatteCoffee
工厂类:
public class CoffeeFactory {
// 1. 定义容器对象存储咖啡对象
private static HashMap<String, Coffee> map = new HashMap<>();
// 2. 加载配置文件,并创建该配置文件里类的对象并进行存储(只需要加载一次)
static {
// 2.1 创建Properties对象
Properties p = new Properties();
// 2.2 调用p对象中的load方法进行配置文件的加载
InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
try {
p.load(is);
// 2.3 从p集合中获取全类名并创建对象
Set<Object> keys = p.keySet();
for (Object key : keys) {
String className = p.getProperty((String) key);
// 2.4 通过反射技术创建对象
Class clazz = Class.forName(className);
Coffee coffee = (Coffee) clazz.newInstance();
// 2.5 将名称和对象存储到容器中
map.put((String) key, coffee);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 根据名称获取对象
public static Coffee createCoffee(String name) {
return map.get(name);
}
}
JDK源码解析 - Collection.iterator()
Collection是抽象工厂;ArrayList是具体工厂
【补】:DateForamt类中的getInstance()、Calendar类中的getInstance()也是工厂模式
原型模式
用一个已经创建的对象作为原型,复制这个原型对象来创建一个和原型对象相同的新对象。
包含的角色:
- 抽象原型类:规定了具体原型对象必须实现的clone()方法
- 具体原型类:实现抽象原型类中的clone()方法,他是可以被复制的对象
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同。对于非基本类型属性,克隆对象和源对象指向的是同一块内存空间
深克隆:创建一个新对象,属性中的引用的其他对象也会被克隆,不会指向原有对象地址。
引例1:克隆对象
具体原型对象
:
public class Relizetype implements Cloneable { // 必须实现Cloneable接口:否则调用clone()会抛出CloneNotSupportedException
public Relizetype() {
System.out.println("具体的原型类创建成功");
}
@Override
public Relizetype clone() throws CloneNotSupportedException { // clone()方法是在Object类里的
System.out.println("具体原型复制成功");
return (Relizetype) super.clone();
}
}
测试类
:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
// 创建原型对象
Relizetype relizetype = new Relizetype();
// 调用原型类中的clone()方法进行对象的克隆
Relizetype clone = relizetype.clone();
System.out.println(relizetype == clone); // false
}
}
必须实现Cloneable接口:否则调用clone()会抛出CloneNotSupportedException。
重写clone()方法:通常需将其改为public访问权限,并返回具体类型。
clone() 方法创建了一个新的对象,而不是返回原对象的引用,因为java的Object.clone()方法是一个native方法,不会调用构造方法,而是直接分配内存并复制数据
引例2.1:三好学生奖状分发(浅克隆)
奖状类:
@Data
public class Citation implements Cloneable {
// 三好学生上的姓名
private String name;
@Override
public Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
public void show() {
System.out.println(name + "同学被评为三好学生");
}
}
测试类:
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原型对象
Citation citation = new Citation();
// 2. 克隆奖状对象
Citation citation1 = citation.clone();
citation.setName("张三");
citation1.setName("李四");
citation.show(); // 张三同学被评为三好学生
citation1.show(); // 李四同学被评为三好学生
}
}
使用场景
- 对象的创建非常复杂,可以使用原型模式快捷创建对象(原型对象的所属类必须实现clone()方法)
- 性能和安全的要求比较高
引例2.2:三好学生奖状分发(深克隆)
学生类:
@Data
@Accessors(chain = true)
public class Student {
// 学生姓名
private String name;
}
奖状类:
@Data
public class Citation implements Cloneable {
private Student student;
@Override
public Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
public void show() {
System.out.println(student.getName() + "同学被评为三好学生");
}
}
测试类:
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原型对象
Citation citation = new Citation();
Student stu = new Student().setName("张三");
citation.setStudent(stu);
// 2. 克隆奖状对象
Citation citation1 = citation.clone();
Student stu1 = citation1.getStudent();
stu1.setName("李四");
citation.show(); // 李四同学被评为三好学生
citation1.show(); // 李四同学被评为三好学生
}
}
【
问题
】由上边测试结果可知,修改了citation1成员变量的值的同时,也修改了citation对象的值
【产生原因
】这是因为stu和stu1此时是一个对象(这就是浅克隆),此时将stu1的属性改成“李四”,导致stu的属性也变成“李四”
【修改
】:把浅克隆变成深克隆(使用序列化和反序列化实现)
public class CitationTest1 {
public static void main(String[] args) throws Exception {
// 1. 创建原型对象
Citation citation = new Citation();
Student stu = new Student().setName("张三");
citation.setStudent(stu);
// 把对象写入文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); // 对象输出流对象
oos.writeObject(citation); // 写对象
oos.close(); // 释放资源
// 从文件中读取对象 (2. 克隆奖状对象)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
Citation citation1 = (Citation) ois.readObject();
citation1.getStudent().setName("李四");
ois.close();
citation.show(); // 张三同学被评为三好学生
citation1.show(); // 李四同学被评为三好学生
}
}
Citation类和Student类都必须实现Serializable接口,否则会抛NotSerializableException异常
【修改
】:把浅克隆变成深克隆(在重写clone()方法的时候调用属性的clone()方法)
奖状类:
@Data
public class Citation implements Cloneable, Serializable {
private Student student;
@Override
public Citation clone() throws CloneNotSupportedException {
Citation clone = (Citation) super.clone();
clone.setStudent(student.clone()); // 深拷贝
return clone;
}
public void show() {
System.out.println(student.getName() + "同学被评为三好学生");
}
}
学生类:
@Data
@Accessors(chain = true)
public class Student implements Serializable, Cloneable {
// 学生姓名
private String name;
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
测试类:
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原型对象
Citation citation = new Citation();
Student stu = new Student().setName("张三");
citation.setStudent(stu);
// 2. 克隆奖状对象
Citation citation1 = citation.clone();
citation1.getStudent().setName("李四");
citation.show(); // 张三同学被评为三好学生
citation1.show(); // 李四同学被评为三好学生
}
}
建造者模式
将复杂对象的构建和表示分离,使同样的构建过程可以创建不同的表示。
建造者建造的产品一般需要有较多的共同点,组成部分需要相似(如果产品之间差异比较大,不适合使用建造者模式)
- 产品类(Product):要创建的复杂对象
- 抽象建造者类(Builder):这个接口规定要实现复杂对象那部分的创建,不涉及具体的对象创建
- 具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件的具体创建方法(强调装配的过程)
- 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,不涉及具体产品信息,只保证对象各个部分完整创建或按照某种顺序创建
引例:创建共享单车
【需求
】:自行车包含了车架、车座等组件的生产;车架又有碳纤维,铝合金等材质;车座有橡胶、真皮的材质
Bike类:产品类(车架、车座组件)
Builder:抽象建造者(MobikeBuilder、OfoBuilder是具体的建造者)
Director:指挥者
产品类:
@Data
public class Bike {
/*车架*/
private String frame;
/*车座*/
private String seat;
}
抽象构建者:
public abstract class Builder {
/*Bike对象*/
protected Bike bike = new Bike(); // 目前还没有组装组件(指挥者做)
/*构建车架*/
public abstract void buildFrame();
/*构建车座*/
public abstract void buildSeat();
/*构建自行车*/
public abstract Bike createBike();
}
具体构建者1(摩拜单车):
public class MobileBuilder extends Builder{
@Override
public void buildFrame() {
bike.setFrame("碳纤维车架");
}
@Override
public void buildSeat() {
bike.setSeat("真皮车座");
}
@Override
public Bike createBike() {
return bike;
}
}
具体构建者2(ofo单车):
public class OfoBuilder extends Builder{
@Override
public void buildFrame() {
bike.setFrame("铝合金车架");
}
@Override
public void buildSeat() {
bike.setSeat("橡胶车座");
}
@Override
public Bike createBike() {
return bike;
}
}
指挥者类:
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
/*组装自行车*/
public Bike construct() {
builder.buildFrame();
builder.buildSeat();
return builder.createBike();
}
}
测试类:
public class Client {
public static void main(String[] args) {
// 1. 创建指挥者对象
Director director = new Director(new MobileBuilder());
// 2. 让指挥者进行自行车的组装
Bike bike = director.construct();
System.out.println(bike.getFrame());
System.out.println(bike.getSeat());
}
}
Director指挥者类在建造者模式中很重要,是由指挥者类来指导具体的建造者应该如何构建产品,控制调用的先后顺序,向调用者返回完整的产品类。
【改进
】:指挥者类也可以和抽象建造者进行结合:
public abstract class Builder {
/*Bike对象*/
protected Bike bike = new Bike(); // 目前还没有组装组件(指挥者做)
/*构建车架*/
public abstract void buildFrame();
/*构建车座*/
public abstract void buildSeat();
/*构建自行车*/
public abstract Bike createBike();
/*组装自行车*/
public Bike construct() {
this.buildFrame();
this.buildSeat();
return this.createBike();
}
}
这样做虽然可以不用写指挥者类,但是也加重了建造者类的职责,也不符合单一职责原则,如果construct()过于复杂,还是建议封装到Director中。
模式扩展
当一个类的构造方法需要传入很多参数,如果创建这个类的实例,代码的可读性就会很差,就可以使用建造者模式进行重构。
手机类:
@Data
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
/*私有构造方法*/
private Phone(Builder builder) {
this.cpu = builder.cpu;
this.screen = builder.screen;
this.memory = builder.memory;
this.mainboard = builder.mainboard;
}
public static final class Builder {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this; // 为了链式编程
}
public Builder screen(String screen) {
this.screen = screen;
return this;
}
public Builder memory(String memory) {
this.memory = memory;
return this;
}
public Builder mainboard(String mainboard) {
this.mainboard = mainboard;
return this;
}
/*使用构建者创建Phone对象*/
public Phone build() {
return new Phone(this);
}
}
}
测试类:
public class Client {
public static void main(String[] args) {
/*创建手机对象 - 通过构建者对象获取手机对象*/
Phone phone = new Phone.Builder()
.cpu("intel")
.screen("三星")
.memory("金士顿内存条")
.mainboard("华硕")
.build();
System.out.println(phone); // Phone(cpu=intel, screen=三星, memory=金士顿内存条, mainboard=华硕)
}
}
将构建的顺序交给客户,这个相当于lombok里的
@Builder
注解
构建者模式对比
工厂方法模式 vs 建造者模式
- 工厂方法模式:整体对象的创建方式
- 建造者模式:部件构建的过程
抽象工厂模式 vs 建造者模式
- 抽象工厂模式:实现对产品家族的创建,不需要关心建造过程,只关心什么产品由什么工厂生产
- 建造者模式:按照指定的蓝图建造产品,通过组装零件而产生一个新产品
抽象工厂模式:汽车配件生产工厂(生产一个产品族的产品)
建造者模式:骑车组装工厂(通过对配件的组装可以返回一个完整的骑车)