建造者模式(Builder Pattern)

684 阅读5分钟

在设计模式中按照不同的处理方式共包含三大类:创建型模式、结构型模式和行为模式。

创建型模式
工厂方法模式(Factory Method Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
单例模式(Singleton Pattern)

定义

创建者模式又叫建造者模式,是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。

我的理解

我理解的的建造者模式为创建一个复杂的对象 对象有很多属性。有时候不需要很多属性都进行预置 只需要几个比较重要的属性初始化好就可以使用!建造者模式通过链式变成的方式为每个重要的属性初始化好 从而得到一个完整的对象

创建者模式代码

/**
 * @author: yangqiang
 * @create: 2021-02-22 11:35
 */
public class Course {
    private String name;
    private String means;
    private String note;
    private String homework;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMeans() {
        return means;
    }

    public void setMeans(String means) {
        this.means = means;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public String getHomework() {
        return homework;
    }

    public void setHomework(String homework) {
        this.homework = homework;
    }

    public static class CourseBuilder {
        private Course course = new Course();

        public CourseBuilder addName(String name) {
            course.setName(name);
            return this;
        }

        public CourseBuilder addMeans(String means) {
            course.setMeans(means);
            return this;
        }

        public CourseBuilder addNote(String note) {
            course.setNote(note);
            return this;
        }

        public CourseBuilder addHomework(String homework) {
            course.setHomework(homework);
            return this;
        }

        public Course build() {
            return course;
        }
    }
}

建造者模式在Spring中的应用

/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.aspectj.annotation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.reflect.PerClauseKind;

import org.springframework.aop.Advisor;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * Helper for retrieving @AspectJ beans from a BeanFactory and building
 * Spring Advisors based on them, for use with auto-proxying.
 *
 * @author Juergen Hoeller
 * @since 2.0.2
 * @see AnnotationAwareAspectJAutoProxyCreator
 */
public class BeanFactoryAspectJAdvisorsBuilder {

   private final ListableBeanFactory beanFactory;

   private final AspectJAdvisorFactory advisorFactory;

   @Nullable
   private volatile List<String> aspectBeanNames;

   private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();

   private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>();


   /**
    * Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory.
    * @param beanFactory the ListableBeanFactory to scan
    */
   public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
      this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
   }

   /**
    * Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory.
    * @param beanFactory the ListableBeanFactory to scan
    * @param advisorFactory the AspectJAdvisorFactory to build each Advisor with
    */
   public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
      Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
      Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
      this.beanFactory = beanFactory;
      this.advisorFactory = advisorFactory;
   }


   /**
    * Look for AspectJ-annotated aspect beans in the current bean factory,
    * and return to a list of Spring AOP Advisors representing them.
    * <p>Creates a Spring Advisor for each AspectJ advice method.
    * @return the list of {@link org.springframework.aop.Advisor} beans
    * @see #isEligibleBean
    */
   public List<Advisor> buildAspectJAdvisors() {
      List<String> aspectNames = this.aspectBeanNames;

      if (aspectNames == null) {
         synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
               List<Advisor> advisors = new ArrayList<>();
               aspectNames = new ArrayList<>();
               String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                     this.beanFactory, Object.class, true, false);
               for (String beanName : beanNames) {
                  if (!isEligibleBean(beanName)) {
                     continue;
                  }
                  // We must be careful not to instantiate beans eagerly as in this case they
                  // would be cached by the Spring container but would not have been weaved.
                  Class<?> beanType = this.beanFactory.getType(beanName, false);
                  if (beanType == null) {
                     continue;
                  }//是否带有@Aspect 和非ajc编译的类
                  if (this.advisorFactory.isAspect(beanType)) {
                     aspectNames.add(beanName);
                     AspectMetadata amd = new AspectMetadata(beanType, beanName);//创建切面元数据
                     if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                        MetadataAwareAspectInstanceFactory factory =
                              new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                        if (this.beanFactory.isSingleton(beanName)) {
                           this.advisorsCache.put(beanName, classAdvisors);
                        }
                        else {
                           this.aspectFactoryCache.put(beanName, factory);
                        }
                        advisors.addAll(classAdvisors);
                     }
                     else {
                        // Per target or per this.
                        if (this.beanFactory.isSingleton(beanName)) {
                           throw new IllegalArgumentException("Bean with name '" + beanName +
                                 "' is a singleton, but aspect instantiation model is not singleton");
                        }
                        MetadataAwareAspectInstanceFactory factory =
                              new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                        this.aspectFactoryCache.put(beanName, factory);
                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                     }
                  }
               }
               this.aspectBeanNames = aspectNames;
               return advisors;
            }
         }
      }

      if (aspectNames.isEmpty()) {
         return Collections.emptyList();
      }
      List<Advisor> advisors = new ArrayList<>();
      for (String aspectName : aspectNames) {
         List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
         if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
         }
         else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
         }
      }
      return advisors;
   }

   /**
    * Return whether the aspect bean with the given name is eligible.
    * @param beanName the name of the aspect bean
    * @return whether the bean is eligible
    */
   protected boolean isEligibleBean(String beanName) {
      return true;
   }

}

优点

  • 使用建造者模式可以使客户端不必知道产品内部组成的细节。
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展。
  • 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。

缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

一般情况下,我们更习惯使用静态内部类的方式实现建造者模式,即一个产品类内部自动带有一个具体建造者,由它负责该产品的组装创建,不再需要 Builder 和 Director。这样做可以使产品表示与创建之间的联系更加紧密,结构更加紧凑,同时使得建造者模式更加简洁。如果采用静态内部类形式实现建造者模式,则《建造者模式实现链式赋值》一节的示例可以改写如下。

与抽象工厂模式对比

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族 。
  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车