Skip to content

Java 创造型模式

AI 整理版

本篇已整理为更适合学习与复习的笔记结构,欢迎前往阅读:创造型模式-AI整理版

  创造型模式是设计模式中的一类,它主要用于处理对象的创建,隐藏对象的创建细节,提供更加灵活的对象创建方式,降低系统的耦合度。

   常见的创造型模式包括:

  1. 简单工厂模式(Simple Factory Pattern)
  2. 工厂方法模式(Factory Method Pattern)
  3. 抽象工厂模式(Abstract Factory Pattern)
  4. 单例模式(Singleton Pattern)
  5. 原型模式(Prototype Pattern)
  6. 建造者模式(Builder Pattern)

  其中,简单工厂模式、工厂方法模式和抽象工厂模式都是工厂模式的不同变体,它们都用于创建对象;

  单例模式用于保证一个类只有一个实例;

  原型模式用于复制对象;

  建造者模式用于创建复杂对象。

简单工厂模式(Simple Factory Pattern)

  简单工厂模式是一种创建型设计模式,它通过一个工厂类来创建不同类型的对象。简单工厂模式将对象的创建过程封装在一个工厂类中,客户端只需要通过工厂类来获取所需的对象,而不需要知道具体的对象创建过程。

  在简单工厂模式中,工厂类负责创建不同类型的对象,并且可以根据客户端的需求来创建不同的对象。工厂类通常包含一个静态方法,该方法接收一个参数,根据参数的不同来创建不同类型的对象。

  简单工厂模式的优点是可以将对象的创建过程封装起来,客户端不需要知道具体的对象创建过程,从而减少了客户端的耦合度。同时,简单工厂模式也可以提高代码的复用性,因为可以在不同的客户端中重复使用同一个工厂类。

  简单工厂模式的缺点是当需要创建新类型的对象时,需要修改工厂类的代码,从而违反了开放-封闭原则。此外,简单工厂模式也会导致工厂类的代码变得过于复杂,难以维护。

如何使用

在Spring Boot中使用简单工厂模式,可以通过以下步骤实现:

  1. 定义一个动物接口Animal,并且实现接口:

    java
    /**
     * @description: 动物接口
     * @author: black tea
     * @date: 2023/3/18 23:30
     */
    public interface Animal {
    
        /**
         * 动物发出声音
         */
        void makeSound();
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/18 23:31
     */
    @Slf4j
    @Service
    public class Cat implements Animal {
    
        @Override
        public void makeSound() {
            log.info("喵喵喵");
        }
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/18 23:31
     */
    @Slf4j
    @Service
    public class Dog implements Animal{
    
        @Override
        public void makeSound() {
            log.info("汪汪汪");
        }
    }
    
    /**
     * @description: 
     * @author: black tea
     * @date: 2023/3/19 0:35
     */
    @Slf4j
    @Service
    public class SeaOtter implements Animal {
    
        @Override
        public void makeSound() {
            log.info("咕噜咕噜");
        }
    }
  2. 创建一个工厂类AnimalFactory,并且通过注入Map形式的Animal接口实现来实现获取对应Animal实现类。

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/18 23:33
     */
    @Component
    public class AnimalFactory {
    
        @Resource
        Map<String, Animal> animalMap;
    
        public Optional<Animal> getAnimal(String animalType){
            if (animalType == null){
                return Optional.empty();
            }
            // 将首字母变小写
            String newAnimalType =  StrUtil.lowerFirst(animalType);
            return Optional.ofNullable(animalMap.get(newAnimalType));
        }
    
    }
  3. 测试使用:

    java
     @Autowired
        private AnimalFactory animalFactory;
    
        /**
         * 测试 简单工厂模式
         */
        @Test
        void testSimpleFactoryModel() {
            log.debug("测试 简单工厂模式");
            Optional<Animal> catOpt = animalFactory.getAnimal(SeaOtter.class.getSimpleName());
            catOpt.ifPresent(Animal::makeSound);
        }

  GitHub学习地址:java-design-patterns/README.md at master · iluwatar/java-design-patterns (github.com)

工厂方法模式(Factory Method Pattern)

  工厂方法模式是一种创建型设计模式,它定义了一个抽象的工厂接口,具体的工厂类实现该接口来创建不同类型的对象。工厂方法模式将对象的创建过程委托给具体的工厂类,从而将对象的创建和使用分离开来。

  在工厂方法模式中,抽象工厂接口中通常包含一个工厂方法,该方法由具体的工厂类来实现,用于创建不同类型的对象。客户端通过调用工厂方法来获取所需的对象,而不需要知道具体的对象创建过程。

  工厂方法模式的优点是可以将对象的创建过程和使用过程分离开来,从而提高代码的灵活性和可维护性。同时,工厂方法模式也符合开放-封闭原则,因为可以通过添加新的工厂类来扩展系统的功能。

  工厂方法模式的缺点是需要定义大量的工厂类,从而增加了代码的复杂度。此外,工厂方法模式也可能导致代码的重复,因为不同的工厂类可能会创建相同类型的对象。

  总的来说,工厂方法模式适用于需要创建一系列相关的对象,但是具体的对象类型在运行时才能确定的情况下。

如何使用

在Spring Boot中使用工厂方法模式,可以通过以下步骤实现:

  1. 定义一个接口UserService,并且实现接口UserServiceImpl:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 1:08
     */
    public interface UserService {
    
        void addUser(Map<String, Object> params);
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 1:10
     */
    @Slf4j
    @Import(SpringUtil.class) // 如果需要在这里调用Spring管理的Bean,需要导入 ApplicationContext
    public class UserServiceImpl implements UserService {
    
        @Override
        public void  addUser(Map<String, Object> params) {
            log.info("添加用户,参数是:{}", JSONUtil.toJsonStr(params));
    
           Optional.ofNullable((Cat) SpringUtil.getBean("cat"))
                   .ifPresent(Cat::makeSound);
    
        }
    }
  2. 创建工厂类UserServiceFactory并且实现FactoryBean接口,重写 getObject方法返回一个UserServiceImpl对象:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 1:12
     */
    @Component
    public class UserServiceFactory implements FactoryBean<UserService> {
    
        @Override
        public UserService getObject() throws Exception {
            return new UserServiceImpl();
        }
    
        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
  3. 单元测试使用:

    java
    @Autowired
        private UserService userService;
    
        /**
         * 测试 工厂方法模式
         */
        @Test
        public void testFactorymethod() throws Exception {
            log.debug("测试 工厂方法模式");
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("username", "张三");
            userMap.put("age", 28);
            userService.addUser(userMap);
        }

  GitHub学习地址:java-design-patterns/README.md at master · iluwatar/java-design-patterns (github.com)

抽象工厂模式(Abstract Factory Pattern)

  抽象工厂模式是一种创建型设计模式,它定义了一个抽象的工厂接口,具体的工厂类实现该接口来创建一组相关的对象。抽象工厂模式将对象的创建过程封装在一个工厂类中,客户端只需要通过工厂类来获取所需的对象,而不需要知道具体的对象创建过程。

  在抽象工厂模式中,抽象工厂接口中通常包含多个工厂方法,每个工厂方法用于创建一个相关的对象。具体的工厂类实现这些工厂方法来创建一组相关的对象。客户端通过调用工厂方法来获取所需的对象,而不需要知道具体的对象创建过程。

  抽象工厂模式的优点是可以将对象的创建过程封装起来,客户端不需要知道具体的对象创建过程,从而减少了客户端的耦合度。同时,抽象工厂模式也可以提高代码的复用性,因为可以在不同的客户端中重复使用同一个工厂类。

  抽象工厂模式的缺点是当需要创建新类型的对象时,需要修改抽象工厂接口和所有的具体工厂类的代码,从而违反了开放-封闭原则。此外,抽象工厂模式也会导致工厂类的代码变得过于复杂,难以维护。

  总的来说,抽象工厂模式适用于需要创建一组相关的对象,且这些对象的类型在运行时才能确定的情况下。

如何使用

在Spring Boot中使用抽象工厂模式,可以通过以下步骤实现:

  这里的代码案例场景有支付方式和小程序类型,我如下只选择了支付方式了说明,因为两个其实包含的理念一样。

  1. 这里我使用一个支付的业务场景来说明,不过这里做了不同支付方式的案例。

  2. 定义一个支付接口Pay,并且实现该接口:

    java
    /**
     * @description: 支付接口
     * @author: black tea
     * @date: 2023/3/19 14:40
     */
    public interface Pay {
    
        void pay(Map<String, Object> payParams);
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 14:42
     */
    @Slf4j
    public class AliPayService implements Pay {
    
        @Override
        public void pay(Map<String, Object> payParams) {
            log.info("支付宝支付");
        }
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 14:41
     */
    @Slf4j
    public class WeChatPayService implements Pay {
    
        @Override
        public void pay(Map<String, Object> payParams) {
            log.info("微信支付");
        }
    }
  3. 定义一个支付方式工厂接口AbstractPayFactory,里面存在两个方法,分别返回不同支付方式的对象。

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 14:44
     */
    public interface AbstractPayFactory {
    
        Optional<AliPayService> createAliPay();
    
        Optional<WeChatPayService> createWxChatPay();
    
    }
  4. 创建一个工厂实现类ConcretePayFactory来实现AbstractPayFactory。

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 14:46
     */
    @Service
    public class ConcretePayFactory implements AbstractPayFactory {
    
        @Override
        public Optional<AliPayService> createAliPay() {
            return Optional.of(new AliPayService());
        }
    
        @Override
        public Optional<WeChatPayService> createWxChatPay() {
            return Optional.of(new WeChatPayService());
        }
    }
  5. 单元测试使用:

    java
        @Autowired
        private AbstractPayFactory payFactory;
    
        /**
         * 测试 抽象工厂方法
         */
        @Test
        void testAbstractPayFactory() {
            log.debug("测试 抽象工厂方法");
            
            Map<String, Object> payMap = new HashMap<>();
            payMap.put("user", "张三");
            payMap.put("amount", new BigDecimal("22.5"));
    
            // 测试 支付
            payFactory.createAliPay()
                    .ifPresent(pay -> {
                        payMap.put("payMethod", "支付宝");
                        pay.pay(payMap);
                    });
            payFactory.createWxChatPay()
                    .ifPresent(pay -> {
                        payMap.put("payMethod", "支付宝");
                        pay.pay(payMap);
                    });
        }

  GitHub学习地址:java-design-patterns/README.md at master · iluwatar/java-design-patterns (github.com)

单例模式(Singleton Pattern)

  单例模式是一种创建型设计模式,它的目的是确保在整个应用程序中只有一个类的实例,并提供全局访问点。实现单例模式的类只有一个实例,并提供访问该实例的全局方法。

  单例模式的优点包括:

  1. 保证只有一个实例存在,减少了内存开销和系统资源的浪费。
  2. 提供了全局访问点,方便了代码的调用和管理。

  但是单例模式也有一些缺点,比如:

  1. 单例类的职责不能过重,否则会导致代码的复杂性和可维护性下降。
  2. 单例类的扩展性不高,如果需要添加新的功能,可能需要修改单例类的代码,这可能会导致系统的不稳定。

  总之,单例模式是一种非常常用的设计模式,它可以在需要的时候方便地创建唯一的实例,并提供全局访问点,从而提高代码的可维护性和可读性。

如何使用

在Spring Boot中使用单例模式,可以通过以下步骤实现:

这里写了三种单例,分别是:

  1. Spring指定为单例,但是存在线程安全问题。

    java
    /**
     * @description: 非线程安全
     * @author: black tea
     * @date: 2023/3/19 16:15
     */
    @Component
    @Scope("singleton") // 指定类型为单例,实际上默认就是单例
    public class MySingleton {
    
    }
  2. 双重锁单例,用于解决线程安全问题。

    java
    /**
     * @description: 双重检查锁来确保线程安全,但是这样会被反射获得
     * @author: black tea
     * @date: 2023/3/19 16:15
     */
    @Component
    @Singleton // 用于标记一个类为单例模式。它的作用是告诉Spring框架,在整个应用程序中只需要创建一个该类的实例。
    public class MySingleton2 {
    
        private static volatile MySingleton2 instance;
    
        private MySingleton2() {}
    
        public static MySingleton2 getInstance() {
            if (instance == null) {
                synchronized (MySingleton2.class) {
                    if (instance == null) {
                        instance = new MySingleton2();
                    }
                }
            }
            return instance;
        }
    }
  3. 内部静态类,用于解决线程安全问题。

    java
    /**
     * @description: 静态内部类实现
     * @author: black tea
     * @date: 2023/3/19 16:40
     *
     * 在这个示例中,使用@Component注解标记了MySingleton类,以便Spring框架能够将该类识别为一个可注入的bean。
     * 静态内部类SingletonHolder包含了一个静态实例变量INSTANCE,该变量在类加载时被初始化,且只会被初始化一次。由于静态内部类的加载是线程安全的,因此可以保证在多线程环境下,只有一个实例被创建。
     * 在getInstance()方法中,直接返回SingletonHolder.INSTANCE变量,这样就可以获取到该类的实例。
     */
    @Component
    public class MySingleton3 {
    
        private MySingleton3() {}
    
        private static class SingletonHolder {
            private static final MySingleton3 INSTANCE = new MySingleton3();
        }
    
        public static MySingleton3 getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
  4. 测试使用:

    java
      	@Autowired
        private MySingleton mySingleton1;
        @Autowired
        private MySingleton mySingleton2;
        @Autowired
        private MySingleton2 mySingleton21;
        @Autowired
        private MySingleton2 mySingleton22;
        @Autowired
        private MySingleton3 mySingleton31;
        @Autowired
        private MySingleton3 mySingleton32;
    
        /**
         * 测试 单例模式
         */
        @Test
        void testSingleton(){
            log.info("测试 单例模式");
    
            // 线程不安全之单例模式
            log.info("线程不安全之单例模式{}", mySingleton1==mySingleton2?"成功":"失败");
    
            /**
             * 双重检查锁之单例模式
             *
             *  两种使用方式
             *   1. MySingleton2.getInstance()
             *
             *   2. @Autowired
             *      private MySingleton2 mySingleton22;
             *
             *   注意:
             *      1. 第一种方法不被Spring所管理,无法访问其他bean。
             *      2. 虽然该类是单例,但并不代表两种方式的到的对象时同一个哦。
             */
            MySingleton2 instance1 = MySingleton2.getInstance();
            MySingleton2 instance2 = MySingleton2.getInstance();
            log.info("双重检查锁之单例模式{}", instance1==instance2?"成功":"失败");
            log.info("双重检查锁之单例模式{}", mySingleton21==mySingleton22?"成功":"失败");
            log.warn("双重检查锁之单例模式,mySingleton21 == instance1的结果为:{},由此可见,方式1和方式2的到的对象可不是同一个哦。", mySingleton21==instance1);
    
            /**
             * 内部静态类之单例模式
             *  1. MySingleton3.getInstance()
             *
             *  2. @Autowired
             *     private MySingleton3 mySingleton31;
             *
             *  注意:
             *   1. 第一种方法不被Spring所管理,无法访问其他bean。
             *   2. 虽然该类是单例,但并不代表两种方式的到的对象时同一个哦。
             */
            log.info("内部静态类之单例模式{}", mySingleton31==mySingleton32?"成功":"失败");
            MySingleton3 instance11 = MySingleton3.getInstance();
            MySingleton3 instance22 = MySingleton3.getInstance();
            log.info("内部静态类之单例模式{}", instance11==instance22?"成功":"失败");
            log.warn("内部静态类之单例模式,mySingleton31 == instance21的结果为:{},由此可见,方式1和方式2的到的对象可不是同一个哦。", mySingleton31==instance11);
        }

  GitHub学习地址:Java-design-patterns/singleton at master ·iluwatar/java-design-patterns (github.com)

原型模式(Prototype Pattern)

  原型模式是一种创建型设计模式,其核心思想是通过复制已有对象来创建新的对象,而不是通过实例化类来创建新的对象。原型模式是一种基于对象的复制技术,它可以在不知道对象具体实现的情况下创建新的对象,同时可以避免创建大量的重复对象,提高系统的性能和效率。

  在原型模式中,原型类是一个可被复制的对象,它定义了一个克隆方法,用于复制自身并返回一个新的对象实例。克隆方法通常是通过实现Java中的Cloneable接口来实现的。

  使用原型模式的主要优点是可以减少对象的创建次数,提高系统的性能和效率,同时也可以避免对象的重复创建。原型模式的主要缺点是需要实现Cloneable接口,并重写clone方法,这对于一些复杂的对象来说可能会比较困难。

  总之,原型模式是一种非常实用的设计模式,它可以在需要创建大量对象的情况下,提高系统的性能和效率,同时也可以避免对象的重复创建。

如何使用

在Spring Boot中使用原型模式,可以通过以下步骤实现:

  1. 定义一个原型类Prototype实现Cloneable接口:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:04
     */
    public class Prototype implements Cloneable {
    
        private String name;
    
        public Prototype(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public Prototype clone() throws CloneNotSupportedException {
            return (Prototype) super.clone();
        }
    
    }
  2. 创建一个配置类ProtoTypeConfig,用来定义Prototype类:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:08
     */
    @Configuration
    public class ProtoTypeConfig {
    
        @Bean
        @Scope("prototype")
        public Prototype prototype(){
            return new Prototype("prototype");
        }
    }
  3. 单元测试使用:

    java
       @Autowired
        private BeanFactory beanFactory;
        @Autowired
        private Prototype prototype11;
        @Autowired
        private Prototype prototype22;
    
        /**
         * 测试 原型模式
         * 结果: 原型返回的是新的对象,使用的是深克隆拷贝哦。
         */
        @Test
        void testPrototype() throws CloneNotSupportedException {
            log.info("测试 原型模式");
            /**
             * 通过 beanFactory 获取
             */
            Prototype prototype1 = beanFactory.getBean(Prototype.class);
            Prototype prototype2 = prototype1.clone();
            log.info(prototype1.getName()); // 输出 "prototype"
            log.info(prototype2.getName()); // 输出 "prototype"
            prototype2.setName("newPrototype");
            log.info(prototype1.getName()); // 输出 "prototype"
            log.info(prototype2.getName()); // 输出 "newPrototype"
    
            /**
             * 通过  @Autowired 获取
             */
            log.info("prototype11==prototype22,结果为:{}", prototype11==prototype22); // prototype1==prototype2,结果为:false
        }

  GitHub学习地址:Java 设计模式/原型在大师 ·iluwatar/java-design-patterns (github.com)

建造者模式(Builder Pattern)

  建造者模式是一种创建型设计模式,它允许您创建复杂的对象,同时将其构造过程与表示分离。它涉及将构造逻辑封装在一个单独的对象中,这使得您可以改变一个对象的内部表示方式,而不会影响到客户端代码。

  在建造者模式中,您将一个复杂对象的构造过程分解成多个简单的步骤,并将每个步骤的实现委托给一个单独的建造者对象。客户端代码只需指定要构建的对象类型和所需的步骤,然后将它们传递给相应的建造者对象,以便构建出所需的对象。

  建造者模式的优点包括:

  1. 可以隐藏对象的复杂构造过程,使客户端代码更简洁。
  2. 可以改变对象的内部表示方式,而不会影响到客户端代码。
  3. 可以将同一构造过程用于不同的对象,提高代码的复用性。
  4. 可以将构造逻辑与表示分离,使得代码更易于维护。

  建造者模式的缺点包括:

  1. 建造者对象的数量可能会增加,增加代码的复杂性。
  2. 构造过程的顺序可能会影响最终对象的表示方式。
  3. 对象的构造过程可能会变得更加复杂,需要更多的代码来实现。

  总之,建造者模式是一种有效的创建复杂对象的方法,它可以将构造逻辑与表示分离,提高代码的复用性和可维护性。

如何使用

在Spring Boot中使用建造者模式,可以通过以下步骤实现:

将一个User对象(建造者)转化为UserEntity对象的场景。其实如果单讲如何创建建造者,User类已经可以实现了,但是使用时会存在一些转化的问题,例如:User user = mapper.convertValue(userEntity, User.class);

转化时会报错,因为User里缺少了UserEntity对象里的一些属性,所以我这里考虑之下将我如何使用的方式进行编写。

  1. 定义一个建造者User类,一个UserEntity类,后者类属性比前者多:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:36
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder // 实现建造者
    public class User {
        private int id;
        private String username;
        private String email;
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:36
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserEntity{
    
        private int id;
        private String username;
        private String email;
        private Map<String, Object> other;
    }
  2. 因为我使用的mapstruct(以下简称ms),所以需要在pom里面加入两个依赖:

    xml
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
    </dependency>
  3. 导入依赖后,创建一个接口UserMapper:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 20:17
     */
    @Mapper(componentModel = "spring")
    public interface UserMapper {
    
        UserEntity toEntity(User user);
    
        User toUser(UserEntity entity);
    }
  4. 定义一个接口UserService并实现:

    java
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:38
     */
    public interface UserService {
    
        User getUserById(int id) throws JsonProcessingException;
    }
    
    /**
     * @description:
     * @author: black tea
     * @date: 2023/3/19 19:38
     */
    @Service
    public class UserServiceImpl implements UserService {
    
        @Resource
        private UserMapper userMapper;
    
        @Override
        public User getUserById(int id) throws JsonProcessingException {
            // 假设从数据库中去到userEntity
            UserEntity userEntity = this.daoGetUserById(id);
            // 1. 将普通对象里的属性一个一个设置到构造者对象中
            User build = User.builder()
                    .id(id)
                    .username(userEntity.getUsername())
                    .email(userEntity.getEmail())
                    .build();
    
            // 2. 使用 MapStruct(推荐)
            User toUser = userMapper.toUser(userEntity);
            UserEntity toEntity = userMapper.toEntity(build);
    
            // 3. 使用jackson
            ObjectMapper mapper = new ObjectMapper();
            // 将构造者对象转为普通对象
            UserEntity newUserEntity = mapper.readValue(
                    mapper.writeValueAsString(build),
                    UserEntity.class
            );
            // 存在缺少的对象时会报错,例如现在缺少other,这种就需要自定义序列化
    //        User user = mapper.convertValue(userEntity, User.class);
    
            // 4. BeanUtils.copyProperties()
            User user = User.builder().build();
            BeanUtils.copyProperties(userEntity, user);
    
            return build;
        }
    
        private UserEntity daoGetUserById(int id){
            UserEntity userEntity = new UserEntity();
            userEntity.setId(id);
            userEntity.setUsername("张三");
            userEntity.setEmail("xxx@xx.com");
            Map<String, Object> other = new HashMap<>();
            other.put("icon", "https://icon.png");
            userEntity.setOther(other);
            return userEntity;
        }
    }
  5. 单元测试使用:

    java
      @Autowired
        private com.blacktea.creationalpatterns.builderpattern.servce.UserService userService1;
    
        /**
         * 测试 建造者模式
         * @throws JsonProcessingException
         */
        @Test
        void testBuilderPattern() throws JsonProcessingException {
            log.info("测试 建造者模式");
            
            User user = userService1.getUserById(1);
            log.info("打印user信息:{}", user.toString());
        }

    注意:ms是根据类型、属性名称之间进行自动转换的,如下就是本次案例转换后生成的类:

    java
    @Generated(
        value = "org.mapstruct.ap.MappingProcessor",
        date = "2023-03-23T18:44:41+0800",
        comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_271 (Oracle Corporation)"
    )
    @Component
    public class UserMapperImpl implements UserMapper {
    
        @Override
        public UserEntity toEntity(User user) {
            if ( user == null ) {
                return null;
            }
    
            UserEntity userEntity = new UserEntity();
    
            userEntity.setId( user.getId() );
            userEntity.setUsername( user.getUsername() );
            userEntity.setEmail( user.getEmail() );
    
            return userEntity;
        }
    
        @Override
        public User toUser(UserEntity entity) {
            if ( entity == null ) {
                return null;
            }
    
            UserBuilder user = User.builder();
    
            user.id( entity.getId() );
            user.username( entity.getUsername() );
            user.email( entity.getEmail() );
    
            return user.build();
        }
    }

  GitHub学习地址:java-design-patterns/localization/zh/builder at master · iluwatar/java-design-patterns (github.com)