写点什么

GoF23 中的对象创建模式!

用户头像
Arvin
关注
发布于: 2021 年 01 月 19 日
GoF23 中的对象创建模式!

试图在实际的场景下,使用合适的方式处理对象的创建, 来避免由对象创建带来的设计问题。


创建型模式有两个主导思想:

一,将系统中使用的具体类封装起来。

二,隐藏这些具体类的创建和组合方式。


创建型模式又可分为两种模式:

一,对象创建模式(处理对象的创建,是把对象的创建的一部分推迟到另外一个对象中)。

二,类创建模式(处理类的创建,是将它对象的创建推迟到子类中).

工厂方法模式


使用场景:特定类型对象的控制过程比简单地创建一个对象更复杂。如下所示:

代码片段代码摘自 Spring Boot 2.4.X。

 1import org.springframework.boot.*; 2import org.springframework.boot.autoconfigure.*; 3import org.springframework.web.bind.annotation.*; 4 5@RestController 6@SpringBootApplication 7public class Example { 8 9    @RequestMapping("/")10    String home() {11        return "Hello World!";12    }1314    public static void main(String[] args) {15        SpringApplication.run(Example.class, args);16    }17}
复制代码

源码:org.springframework.boot.SpringApplication

 1/** 2 * Run the Spring application, creating and refreshing a new 3 * {@link ApplicationContext}. 4 * @param args the application arguments (usually passed from a Java main method) 5 * @return a running {@link ApplicationContext} 6 */ 7public ConfigurableApplicationContext run(String... args) { 8   StopWatch stopWatch = new StopWatch(); 9   stopWatch.start();10   // 整个run属于工厂方法外,内部实现中也包括多个工厂方法。11   DefaultBootstrapContext bootstrapContext = createBootstrapContext();12   ConfigurableApplicationContext context = null;13   configureHeadlessProperty();15   SpringApplicationRunListeners listeners = getRunListeners(args);16   listeners.starting(bootstrapContext, this.mainApplicationClass);17   try {18      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);19      20      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);21      configureIgnoreBeanInfo(environment);22      23      Banner printedBanner = printBanner(environment);24      25      context = createApplicationContext();26      context.setApplicationStartup(this.applicationStartup);27     28      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);29     30      refreshContext(context);31      32      afterRefresh(context, applicationArguments);33      34      stopWatch.stop();35      if (this.logStartupInfo) {36         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);37      }38      listeners.started(context);39    40      callRunners(context, applicationArguments);41   }42   catch (Throwable ex) {43      handleRunFailure(context, ex, listeners);44      throw new IllegalStateException(ex);45   }4647   try {48      listeners.running(context);49   }50   catch (Throwable ex) {51      handleRunFailure(context, ex, null);52      throw new IllegalStateException(ex);53   }54   return context;55}
复制代码

源码中 SpringApplication.run 静态方法,对于 ApplicationContext 类的创建和控制进行封装,调用方端代码 Example 只需调用 SpringApplication.run(Example.class, args) 就可以应用 SpringBoot 框架了。由此可见一个在工厂方法并不要求,类或者方法的名字上存在 facotry 的字样。工厂方法”这个词也可以指作为“工厂”的方法,这个方法的主要目的就是创建对象,而这个方法不一定在单独的工厂类中。这些方法通常作为静态方法,定义在方法所实例化的类中。工厂方法模式常见于工具包和框架中。同在 SpringApplication 中的启动工厂方法 run 中 第 25 行出现另外一种工厂方法的应用。代码如下:

简单工厂方法调用方代码。

 1//上下文环境简单工厂方法成员变量(函数编程的方式)工厂方法称为第一类的类成员,可以缓解以下问题 2//1.ApplicationContextFactory 如果调用方通过 new ApplicationContextFactory()方式调,如 ApplicationContextFactory 的构造方法 private 申明,其调用方调用将会失效。 4//2.ApplicationContextFactory 的构造方法 private 申明后 ApplicationContextFactory的所有子类的扩展将会无效报错。 6//3.ApplicationContextFactory 的工厂方式私有化后,所有子类将需要自己有一套工厂方法的实现。 7private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT; 8private WebApplicationType webApplicationType; 9/**10 * Strategy method used to create the {@link ApplicationContext}. By default this11 * method will respect any explicitly set application context class or factory before12 * falling back to a suitable default.13 * @return the application context (not yet refreshed)14 * @see #setApplicationContextClass(Class)15 * @see #setApplicationContextFactory(ApplicationContextFactory)16 */17protected ConfigurableApplicationContext createApplicationContext() {18   return this.applicationContextFactory.create(this.webApplicationType);19}
复制代码

简单工厂方法实现方代码。

 1@FunctionalInterface 2public interface ApplicationContextFactory { 3 4   /** 5    * A default {@link ApplicationContextFactory} implementation that will create an 6    * appropriate context for the {@link WebApplicationType}. 7    */ 8   ApplicationContextFactory DEFAULT = (webApplicationType) -> { 9      try {10         switch (webApplicationType) {11         case SERVLET:12            return new AnnotationConfigServletWebServerApplicationContext();13         case REACTIVE:14            return new AnnotationConfigReactiveWebServerApplicationContext();15         default:16            return new AnnotationConfigApplicationContext();17         }18      }19      catch (Exception ex) {20         throw new IllegalStateException("Unable create a default ApplicationContext instance, "21               + "you may need a custom ApplicationContextFactory", ex);22      }23   };2425   /**26    * Creates the {@link ConfigurableApplicationContext application context} for a27    * {@link SpringApplication}, respecting the given {@code webApplicationType}.28    * @param webApplicationType the web application type29    * @return the newly created application context30    */31   ConfigurableApplicationContext create(WebApplicationType webApplicationType);32   ......33}
复制代码

上述代码中的工厂方法(简单工厂方法)模式通常伴随着对象的具体类型与工厂具体类型的一一对应,调用方代码根据需要选择合适的具体类型工厂使用。然而,这种选择可能包含复杂的逻辑。这时,可以创建一个单一的工厂类,用以包含这种选择逻辑,根据参数的不同选择实现不同的具体对象。

抽象工厂模式

使用场景:调用方代码与对象的创建分离开来。调用方代码仅仅处理抽象类型。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的调用方代码。个人认为 Spring Boot 中的日志代表性很强。如下所示:

源码:org.springframework.boot.SpringApplication 下的工厂方法

 1/**  2 * Returns the {@link Log} for the application. By default will be deduced. 3 * @return the application log 4 */ 5protected Log getApplicationLog() { 6   if (this.mainApplicationClass == null) { 7      return logger; 8   } 9   return LogFactory.getLog(this.mainApplicationClass);10}
复制代码

源码 :Spring framework 5.2.X spring-jcl 模块下 org.apache.commons.logging.LogFactory

 1package org.apache.commons.logging; 2 3public abstract class LogFactory { 4 5   /** 6    * Convenience method to return a named logger. 7    * @param clazz containing Class from which a log name will be derived 8    */ 9   public static Log getLog(Class<?> clazz) {10      return getLog(clazz.getName());11   }1213   /**14    * Convenience method to return a named logger.15    * @param name logical name of the <code>Log</code> instance to be returned16    */17   public static Log getLog(String name) {18      //抽象工厂的接口,可以方便其扩展19      return LogAdapter.createLog(name);20   }21}
复制代码

源码: org.apache.commons.logging.LogAdepter

 1/** 2    * Create an actual {@link Log} instance for the selected API. 3    * @param name the logger name 4    */ 5   public static Log createLog(String name) { 6      switch (logApi) { 7         case LOG4J: 8            return Log4jAdapter.createLog(name); 9         case SLF4J_LAL:10            return Slf4jAdapter.createLocationAwareLog(name);11         case SLF4J:12            return Slf4jAdapter.createLog(name);13         default:14            // Defensively use lazy-initializing adapter class here as well since the15            // java.logging module is not present by default on JDK 9. We are requiring16            // its presence if neither Log4j nor SLF4J is available; however, in the17            // case of Log4j or SLF4J, we are trying to prevent early initialization18            // of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly19            // trying to parse the bytecode for all the cases of this switch clause.20            return JavaUtilAdapter.createLog(name);21      }22   }23}
复制代码

上述代码中 LogFactory 为抽象工厂类,日志输出底层实现由 LogAdapter.createLog 负责,Log 接口则是面向调用方代码的抽象 API。这样一来 LogAdapter.createLog 方式可以扩展更多的实现。调用方只需要面对稳定的抽象 Log 接口即可,使调用方被分离出来。

构造器模式

当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时,当构造过程必须允许被构造的对象有不同的表示时。如下所示:

源码: org.springframework.boot.jdbc.DataSourceBuilder

 1public final class DataSourceBuilder<T extends DataSource> { 2 3   private Class<? extends DataSource> type; 4 5   private final DataSourceSettingsResolver settingsResolver; 6 7   private final Map<String, String> properties = new HashMap<>(); 8 9   @SuppressWarnings("unchecked")10   public T build() {11      Class<? extends DataSource> type = getType();12      DataSource result = BeanUtils.instantiateClass(type);13      maybeGetDriverClassName();14      bind(result);15      return (T) result;16   }1718   //设置连接数据库url19   public DataSourceBuilder<T> url(String url) {20        this.properties.put("url", url);21        return this;22    }23   //设置连接数据库驱动类24    public DataSourceBuilder<T> driverClassName(String driverClassName) {25        this.properties.put("driverClassName", driverClassName);26        return this;27    }28   //设置连接数据库用户名29    public DataSourceBuilder<T> username(String username) {30        this.properties.put("username", username);31        return this;32    }33   //设置连接数据库密码34    public DataSourceBuilder<T> password(String password) {35        this.properties.put("password", password);36        return this;37    }38}
复制代码

以上代码摘自 DataSourceBuilder ,build() 方法构建 DataSource 前,则可以通过类中其它方法如 url,driverClassName,username,password 完成与 DataSource 匹配的设置,返回不同的数据源对象。它将构造代码和表示代码分开,同时方便了你可对构造过程进行更精细的控制。

原型模式

通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。如下所示:

源码: org.springframework.beans.factory.support.AbstractBeanFactory

 1/** Names of beans that are currently in creation. */ 2    private final ThreadLocal<Object> prototypesCurrentlyInCreation = 3            new NamedThreadLocal<>("Prototype beans currently in creation"); 4 5/** 6 * Return an instance, which may be shared or independent, of the specified bean. 7 * @param name the name of the bean to retrieve 8 * @param requiredType the required type of the bean to retrieve 9 * @param args arguments to use when creating a bean instance using explicit arguments10 * (only applied when creating a new instance as opposed to retrieving an existing one)11 * @param typeCheckOnly whether the instance is obtained for a type check,12 * not for actual use13 * @return an instance of the bean14 * @throws BeansException if the bean could not be created15 */16@SuppressWarnings("unchecked")17protected <T> T doGetBean(18      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)19      throws BeansException {20 ......21         else if (mbd.isPrototype()) {22            // It's a prototype -> create a new instance.23            Object prototypeInstance = null;24            try {25               beforePrototypeCreation(beanName);26               prototypeInstance = createBean(beanName, mbd, args);27            }28            finally {29               afterPrototypeCreation(beanName);30            }31            beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);32         }33......34}35/**36     * Callback before prototype creation.37     * <p>The default implementation register the prototype as currently in creation.38     * @param beanName the name of the prototype about to be created39     * @see #isPrototypeCurrentlyInCreation40     */41    @SuppressWarnings("unchecked")42    protected void beforePrototypeCreation(String beanName) {43        Object curVal = this.prototypesCurrentlyInCreation.get();44        if (curVal == null) {45            this.prototypesCurrentlyInCreation.set(beanName);46        }47        else if (curVal instanceof String) {48            Set<String> beanNameSet = new HashSet<>(2);49            beanNameSet.add((String) curVal);50            beanNameSet.add(beanName);51            this.prototypesCurrentlyInCreation.set(beanNameSet);52        }53        else {54            Set<String> beanNameSet = (Set<String>) curVal;55            beanNameSet.add(beanName);56        }57    }5859/**60     * Callback after prototype creation.61     * <p>The default implementation marks the prototype as not in creation anymore.62     * @param beanName the name of the prototype that has been created63     * @see #isPrototypeCurrentlyInCreation64     */65    @SuppressWarnings("unchecked")66    protected void afterPrototypeCreation(String beanName) {67        Object curVal = this.prototypesCurrentlyInCreation.get();68        if (curVal instanceof String) {69            this.prototypesCurrentlyInCreation.remove();70        }71        else if (curVal instanceof Set) {72            Set<String> beanNameSet = (Set<String>) curVal;73            beanNameSet.remove(beanName);74            if (beanNameSet.isEmpty()) {75                this.prototypesCurrentlyInCreation.remove();76            }77        }78    }7980/**81     * Create a bean instance for the given merged bean definition (and arguments).82     * The bean definition will already have been merged with the parent definition83     * in case of a child definition.84     * <p>All bean retrieval methods delegate to this method for actual bean creation.85     * @param beanName the name of the bean86     * @param mbd the merged bean definition for the bean87     * @param args explicit arguments to use for constructor or factory method invocation88     * @return a new instance of the bean89     * @throws BeanCreationException if the bean could not be created90     */91    protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)92            throws BeanCreationException;
复制代码

源码: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  1/**  2 * Central method of this class: creates a bean instance,  3 * populates the bean instance, applies post-processors, etc.  4 * @see #doCreateBean  5 */  6@Override  7protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)  8      throws BeanCreationException {  9   if (logger.isTraceEnabled()) { 10      logger.trace("Creating instance of bean '" + beanName + "'"); 11   } 12   RootBeanDefinition mbdToUse = mbd; 13   // Make sure bean class is actually resolved at this point, and 14   // clone the bean definition in case of a dynamically resolved Class 15   // which cannot be stored in the shared merged bean definition. 16 ...... 17   // Prepare method overrides. 18 ...... 19   try { 20      Object beanInstance = doCreateBean(beanName, mbdToUse, args); 21      if (logger.isTraceEnabled()) { 22         logger.trace("Finished creating instance of bean '" + beanName + "'"); 23      } 24      return beanInstance; 25   } 26   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { 27   ...... 28   } 29   catch (Throwable ex) { 30  ...... 31   } 32} 33/** 34     * Actually create the specified bean. Pre-creation processing has already happened 35     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks. 36     * <p>Differentiates between default bean instantiation, use of a 37     * factory method, and autowiring a constructor. 38     * @param beanName the name of the bean 39     * @param mbd the merged bean definition for the bean 40     * @param args explicit arguments to use for constructor or factory method invocation 41     * @return a new instance of the bean 42     * @throws BeanCreationException if the bean could not be created 43     * @see #instantiateBean 44     * @see #instantiateUsingFactoryMethod 45     * @see #autowireConstructor 46     */ 47    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 48            throws BeanCreationException { 49    // Instantiate the bean. 50        BeanWrapper instanceWrapper = null; 51        if (mbd.isSingleton()) { 52            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 53        } 54        if (instanceWrapper == null) { 55            instanceWrapper = createBeanInstance(beanName, mbd, args); 56        } 57    Object bean = instanceWrapper.getWrappedInstance(); 58 ...... 59   // Initialize the bean instance. 60        Object exposedObject = bean; 61        try { 62      //Populate the bean instance in the given BeanWrapper with the property values from the bean definition. 63            populateBean(beanName, mbd, instanceWrapper); 64            exposedObject = initializeBean(beanName, exposedObject, mbd); 65        } 66        catch (Throwable ex) { 67            ...... 68        } 69......     70} 71 72/** 73     * Populate the bean instance in the given BeanWrapper with the property values 74     * from the bean definition. 75     * @param beanName the name of the bean 76     * @param mbd the bean definition for the bean 77     * @param bw the BeanWrapper with bean instance 78     */ 79    @SuppressWarnings("deprecation")  // for postProcessPropertyValues 80    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { 81  ......   82        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); 83    ......   84        if (pvs != null) { 85            applyPropertyValues(beanName, mbd, bw, pvs); 86        } 87    } 88/** 89     * Apply the given property values, resolving any runtime references 90     * to other beans in this bean factory. Must use deep copy, so we 91     * don't permanently modify this property. 92     * @param beanName the bean name passed for better exception information 93     * @param mbd the merged bean definition 94     * @param bw the BeanWrapper wrapping the target object 95     * @param pvs the new property values 96     */ 97    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { 98    ......  99        MutablePropertyValues mpvs = null;100        List<PropertyValue> original;101        if (pvs instanceof MutablePropertyValues) {102...... 103            original = mpvs.getPropertyValueList();104        }105        else {106            original = Arrays.asList(pvs.getPropertyValues());107        }108    ...... 109        // Create a deep copy, resolving any references for values.110        List<PropertyValue> deepCopy = new ArrayList<>(original.size());111        boolean resolveNecessary = false;112        for (PropertyValue pv : original) {113...... 114        }115        if (mpvs != null && !resolveNecessary) {116            mpvs.setConverted();117        }118        // Set our (possibly massaged) deep copy.119        try {120            bw.setPropertyValues(new MutablePropertyValues(deepCopy));121        }122        catch (BeansException ex) {123...... 124        }125    }126127    /**128     * Initialize the given bean instance, applying factory callbacks129     * as well as init methods and bean post processors.130     * <p>Called from {@link #createBean} for traditionally defined beans,131     * and from {@link #initializeBean} for existing bean instances.132     * @param beanName the bean name in the factory (for debugging purposes)133     * @param bean the new bean instance we may need to initialize134     * @param mbd the bean definition that the bean was created with135     * (can also be {@code null}, if given an existing bean instance)136     * @return the initialized bean instance (potentially wrapped)137     * @see BeanNameAware138     * @see BeanClassLoaderAware139     * @see BeanFactoryAware140     * @see #applyBeanPostProcessorsBeforeInitialization141     * @see #invokeInitMethods142     * @see #applyBeanPostProcessorsAfterInitialization143     */144    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {145    ......   146  }
复制代码

单例模式

单例模式属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。如下所示:

源码: org.springframework.beans.factory.support.AbstractBeanFactory

 1protected <T> T doGetBean( 2      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) 3      throws BeansException { 4 ...... 5         // Create bean instance. 6         if (mbd.isSingleton()) { 7           //1:  8           sharedInstance = getSingleton(beanName, () -> { 9               try {10                  return createBean(beanName, mbd, args);11               }12               catch (BeansException ex) {13                  // Explicitly remove instance from singleton cache: It might have been put there14                  // eagerly by the creation process, to allow for circular reference resolution.15                  // Also remove any beans that received a temporary reference to the bean.16                  destroySingleton(beanName);17                  throw ex;18               }19            });20            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);21         }22  ......23}
复制代码

其 getSingleton 方法继承 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

 1    /** Cache of singleton objects: bean name to bean instance. */ 2    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 3 4  /** Names of beans that are currently in creation. */ 5    private final Set<String> singletonsCurrentlyInCreation = 6            Collections.newSetFromMap(new ConcurrentHashMap<>(16)); 7 8    /** Names of beans currently excluded from in creation checks. */ 9    private final Set<String> inCreationCheckExclusions =10            Collections.newSetFromMap(new ConcurrentHashMap<>(16));1112/**13     * Return the (raw) singleton object registered under the given name,14     * creating and registering a new one if none registered yet.15     * @param beanName the name of the bean16     * @param singletonFactory the ObjectFactory to lazily create the singleton17     * with, if necessary18     * @return the registered singleton object19     */20    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {21    ......22        synchronized (this.singletonObjects) {23        Object singletonObject = this.singletonObjects.get(beanName);24            if (singletonObject == null) {25        ......26                beforeSingletonCreation(beanName);27                boolean newSingleton = false;28              ......29                try {30                    singletonObject = singletonFactory.getObject();31                    newSingleton = true;32                }33                catch (IllegalStateException ex) {34                    ......35                }36                catch (BeanCreationException ex) {37                    ......38                }39                finally {40                  ......41                    afterSingletonCreation(beanName);42                }43                if (newSingleton) {44                    addSingleton(beanName, singletonObject);45                }46            }47            return singletonObject;48        }49}5051/**52     * Callback before singleton creation.53     * <p>The default implementation register the singleton as currently in creation.54     * @param beanName the name of the singleton about to be created55     * @see #isSingletonCurrentlyInCreation56     */57    protected void beforeSingletonCreation(String beanName) {58        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {59            throw new BeanCurrentlyInCreationException(beanName);60        }61    }62    /**63     * Callback after singleton creation.64     * <p>The default implementation marks the singleton as not in creation anymore.65     * @param beanName the name of the singleton that has been created66     * @see #isSingletonCurrentlyInCreation67     */68    protected void afterSingletonCreation(String beanName) {69        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {70            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");71        }72    }73/**74 * Add the given singleton object to the singleton cache of this factory.75 * <p>To be called for eager registration of singletons.76 * @param beanName the name of the bean77 * @param singletonObject the singleton object78 */79protected void addSingleton(String beanName, Object singletonObject) {80   synchronized (this.singletonObjects) {81      this.singletonObjects.put(beanName, singletonObject);82      this.singletonFactories.remove(beanName);83      this.earlySingletonObjects.remove(beanName);84      this.registeredSingletons.add(beanName);85   }86}
复制代码


以下内容摘自 Spring 官方文档对于单例应用的解释:

Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of Four (GoF) patterns book.The GoF singleton hard-codes the scope of an object such that one and only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton is best described as being per-container and per-bean. This means that, if you define one bean for a particular class in a single Spring container, the Spring container creates one and only one instance of the class defined by that bean definition. The singleton scope is the default scope in Spring.

ClassLoader(JDK 提供) : A class loader is an object that is responsible for loading classes.

Spring container(Spring 提供) : In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container.

总结

  • 一个系统需要和它的对象和产品的创建相互独立。

  • 一组相关的对象被设计为一起使用。

  • 隐藏一个类库的具体实现,仅暴露它们的接口。

  • 创建独立复杂对象的不同表示。

  • 一个类希望它的子类实现它所创建的对象。

  • 类的实例化在运行时才指定。

  • 一个类只能有一个实例,而且这个实例能在任何时候访问到。

  • 实例应该能在不修改的情况下具有可扩展性。


Singleton 和 Prototype 的注意事项:

Spring 并不管理 Prototype scope Bean 的整个生命周期。

Singleton Bean 中依赖 Prototype Bean ,Prototype Bean 也将转换为 Singleton。


发布于: 2021 年 01 月 19 日阅读数: 35
用户头像

Arvin

关注

生活黑客35 2019.06.11 加入

向自己发问:“当下我应该做那些事情来增加自己的决心,强化自己的人格,找到继续前行的勇气?”

评论

发布
暂无评论
GoF23 中的对象创建模式!