zoukankan      html  css  js  c++  java
  • 设计模式工厂模式

     

    1、设计模式之工厂

     

    工厂模式是我们最常用的设计模式,学好这个模式当然可以事半功倍,不用关心如何创建,只需要根据相应的需求去获取相应的对象。

    假如我们现在需要得到一个Ipod对象和Mac对象,可能在之前,我们的Ipod和Mac都是new出来了,相当于我们的程序依赖了Ipod类和Mac,但是使用了工厂我们就可以部分解耦,将创建和使用分离。

    设计模式有一条原则,对象要么构造其他对象,要么使用其他对象,绝对不要两者兼顾。如果遵守这一约束,最终可以降低耦合度。

    例如,之前的demo的类图如下:

     

    新依赖关系:

     

     

     

    对于使用者的角度来说只需要得到这些对象即可,并不需要这些对象是如何创建的。对于创建者AppleFactory来说,只需要创建并且实例化对象即可,并不需要知道如何使用。这种关注点的分离既加强了内聚性,又降低了耦合度。

     

    2、基础的简单工厂

     

    简单工厂是最基本的工厂模式的应用,其实在很多场合简单工厂就已经很适用了。

    大致代码如下:

     

    代码
    1
    2
    3  package factory;
    4
    5
    6
    7  import java.util.HashMap;
    8
    9  import java.util.Map;
    10
    11
    12
    13  /**
    14
    15 * User: <a href="mailto:czy88840616@163.com">czy</a>
    16
    17 * Date: 2010-1-23
    18
    19 * Time: 20:28:13
    20
    21 * To change this template use File | Settings | File Templates.
    22
    23 */
    24
    25  public class AppleSimpleFactory {
    26
    27
    28
    29 private static Map<String, Object> beanMap = new HashMap<String, Object>();
    30
    31
    32
    33 /**
    34
    35 * Method getBean ...
    36
    37 *
    38
    39 * @param beanName of type String
    40
    41 * @return Object
    42
    43 */
    44
    45 public Object getBean(String beanName) {
    46
    47 if(beanMap.containsKey(beanName)) {
    48
    49 return beanMap.get(beanName);
    50
    51 }
    52
    53
    54
    55 return null;
    56
    57 }
    58
    59
    60
    61 /**
    62
    63 * Method init ...
    64
    65 */
    66
    67
    68
    69 public void init() {
    70
    71 beanMap.put("Ipod", new Ipod());
    72
    73 beanMap.put("Mac", new Mac());
    74
    75 }
    76
    77
    78
    79 }
    80
    81  

     

     

    我们创建了一个简单的apple工厂,里面创建了两个对象ipod和mac,当我们需要ipod对象的时候就可以直接get出来使用,不需要通过new来新建。

     

    3、抽象了的工厂—抽象工厂abstract factory

     

     

    抽象工厂类似于将工厂再抽象一层,让关注点不在于怎么创建,而在于创建不同的方式。

    例如,A工厂生产ipod的时候需要打印A的牌子,而B工厂生产的时候需要打B的牌子,生产的产品都是一样的,都是ipod,但是其中的工序和方式不同。

     

    例如:

     

    代码
    package factory;



    import java.util.HashMap;

    import java.util.Map;



    /**

    *
    @author <a href="mailto:czy88840616@gmail.com">czy</a>

    *
    @since 2010-2-28 22:03:50

    */

    public abstract class MyAbstractFactory {



    protected static Map<String, Object> beanMap = new HashMap<String, Object>();



    public abstract void create();



    public abstract Product getProduct(String className);



    }

     

     

    A工厂的方法:

     

     

    代码
    package factory;



    /**

    *
    @author <a href="mailto:czy88840616@gmail.com">czy</a>

    *
    @since 2010-2-28 22:16:05

    */

    public class MyAbstractFactoryImpl extends MyAbstractFactory {



    @Override
    public void create() {

    Ipod iPod
    = new Ipod();

    iPod.pasteSign(
    "made by A factory");

    beanMap.put(
    "Ipod", new Ipod());

    beanMap.put(
    "Mac", new Mac());

    }



    @Override
    public Product getProduct(String className) {

    if(beanMap.containsKey(className)) {

    return (Product) beanMap.get(className);

    }



    return null;

    }

    }



     

    B工厂方法类似,其中最主要的就是贴牌的不同。

    抽象工厂用于创建相同的产品但是方式不同的地方。

     

    4、singleton模式

     

    单例模式主要为了控制对象的数目,在使用过程中,只有一个对象存在。

    单例模式的工作原理是,用一个特殊的方法来实例化所需的对象:调用这个方法,检查对象是否已经实例化,如果已经实例化,就返回该对象的一个引用,如果尚未实例化,该方法实例化对象并返回新实例的引用。为了确保这是实例化这个对象的唯一方法,需要将这个类的构造函数定义为保护或者私有的。

     

    一般Singleton模式通常有几种形式:

     

     

    代码
    public class Singleton {



    private Singleton(){}



      
    private static Singleton instance = new Singleton();



      
    //这里提供了一个供外部访问本class的静态方法,可以直接访问  

      
    public static Singleton getInstance() {

        
    return instance;   

       }

    }

     

     

     

     

    第二种形式:

     

     

    代码
    public class Singleton {

      
    private static Singleton instance = null;



      
    public static Singleton getInstance() {



      
    if (instance==null)

        instance=
    new Singleton();

    return instance;   

    }

    }

     

     

    两种的区别是:第二种是lazy加载方式,只有第一次会被初始化,而之后的都可以直接调用。但是第二种会有并发的问题,没有使用synchronized的时候会出现多个实例并存的问题。

     

    Singleton是邪恶的

    http://www.jdon.com/jivejdon/thread/17578

     

    深入singleton可能会演变成double-checked locking (DCL) 模式,比较使用于多线程的情况。

     

    5、spring 的beanFactory

     

    现在工厂模式基本上都可以被spring的core取代,DI的方式已经大量应用于项目。

    Spring创建工厂的接口为beanFactory,默认的像applicationContext都是继承于此接口。

     

     

    Spring提供了一些标志接口,用来改变BeanFactory中的bean的行为。它们包括InitializingBean和DisposableBean。实现这些接口将会导致BeanFactory调用前一个接口的afterPropertiesSet()方法,调用后一个接口destroy()方法,从而使得bean可以在初始化和析构后做一些特定的动作。 

    Debug了spring的源码后,发现spring在创建bean前进行了许多的操作。

    在org.springframework.context.support.AbstractApplicationContext的refresh()方法中。

     

    代码
    public void refresh() throws BeansException, IllegalStateException {

    synchronized (this.startupShutdownMonitor) {

    // Prepare this context for refreshing.

    prepareRefresh();



    // Tell the subclass to refresh the internal bean factory.

    ConfigurableListableBeanFactory beanFactory
    = obtainFreshBeanFactory();



    // Prepare the bean factory for use in this context.

    prepareBeanFactory(beanFactory);



    try {

    // Allows post-processing of the bean factory in context subclasses.

    postProcessBeanFactory(beanFactory);



    // Invoke factory processors registered as beans in the context.

    invokeBeanFactoryPostProcessors(beanFactory);



    // Register bean processors that intercept bean creation.

    registerBeanPostProcessors(beanFactory);



    // Initialize message source for this context.

    initMessageSource();



    // Initialize event multicaster for this context.

    initApplicationEventMulticaster();



    // Initialize other special beans in specific context subclasses.

    onRefresh();



    // Check for listener beans and register them.

    registerListeners();



    // Instantiate all remaining (non-lazy-init) singletons.

    finishBeanFactoryInitialization(beanFactory);



    // Last step: publish corresponding event.

    finishRefresh();

    }



    catch (BeansException ex) {

    // Destroy already created singletons to avoid dangling resources.

    beanFactory.destroySingletons();



    // Reset 'active' flag.

    cancelRefresh(ex);



    // Propagate exception to caller.

    throw ex;

    }

    }

    }

     

    红色部分代码为spring创建和放入beanfacoty的主要代码。

     

    跟踪spring的初始化过程来看,最终进行的初始化类的工作在org.springframework.beans.BeanUtils类的instantiateClass方法中。

     

     

    代码
    public static Object instantiateClass(Class clazz) throws BeanInstantiationException {

    Assert.notNull(clazz,
    "Class must not be null");

    if (clazz.isInterface()) {

    throw new BeanInstantiationException(clazz, "Specified class is an interface");

    }

    try {

    return instantiateClass(clazz.getDeclaredConstructor((Class[]) null), null);

    }

    catch (NoSuchMethodException ex) {

    throw new BeanInstantiationException(clazz, "No default constructor found", ex);

    }

    }

     

     

    最底层的实现一定是为jdk的反射方式。

    代码
    public static Object instantiateClass(Constructor ctor, Object[] args) throws BeanInstantiationException {

    Assert.notNull(ctor,
    "Constructor must not be null");

    try {

    ReflectionUtils.makeAccessible(ctor);

    return ctor.newInstance(args);

    }

    catch (InstantiationException ex) {

    throw new BeanInstantiationException(ctor.getDeclaringClass(),

    "Is it an abstract class?", ex);

    }

    catch (IllegalAccessException ex) {

    throw new BeanInstantiationException(ctor.getDeclaringClass(),

    "Has the class definition changed? Is the constructor accessible?", ex);

    }

    catch (IllegalArgumentException ex) {

    throw new BeanInstantiationException(ctor.getDeclaringClass(),

    "Illegal arguments for constructor", ex);

    }

    catch (InvocationTargetException ex) {

    throw new BeanInstantiationException(ctor.getDeclaringClass(),

    "Constructor threw exception", ex.getTargetException());

    }

    }
  • 相关阅读:
    生于忧患,死于安乐
    【网络流24题】骑士共存问题
    【网络流24题】最长不下降子序列问题
    【网络流24题】太空计划问题
    SG函数
    【网络流24题】餐巾计划问题
    【APIO2019】奇怪装置
    【HEOI2016/TJOI2016】游戏
    【SDOI2015】星际战争
    【CQOI2009】跳舞
  • 原文地址:https://www.cnblogs.com/xiziyin/p/1676021.html
Copyright © 2011-2022 走看看