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

    工厂方法

    定义 :定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行

    创建型 :创建型

    适用场景

    • 创建对象需要大量重复的代码
    • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
    • 一个类通过其子类来指定创建哪个对象

    优点

    • 用户只需要关心所需产品对应的工厂,无需关心创建的细节
    • 加入新产品符合开闭原则,提高可扩展性

    缺点

    • 类的个数容易过多,增加复杂度

    • 增加了系统的抽象性和理解难度

    UML类图

    Product:抽象产品类,也可以是接口,具体看实际情况而定

    ConcreteProduct:具体产品实现类

    Creator:抽象工厂类,也可以是接口,定义了供子类实现的生产产品的抽象方法,也即是将对象的实例化推迟到子类去做

    ConcreteFactory:具体工厂,真正生产产品的类

    示例

    在上篇简单工厂模式的示例中,不同品牌的打印机对象创建是委托给一个打印机工厂,创建逻辑都堆砌在一个工厂方法中通过if分支判断进行,一旦要引入新品牌的打印机驱动,就需要改造工厂类的方法,违反了开闭原则。在工厂方法中,每一个种产品都有一个对应的工厂类进行产品对象创建,引入一个新的产品,只需要添加新的工厂即可。下面改造下简单工厂模式中的示例

    • 定义一个抽象产品接口(也可以是抽象类),定义了所有打印机产品都具有的功能
    /**
     * 各个打印机需要实现的打印机接口(产品接口)
     */
    public interface IPrinter {
    
        void print();
    
    }
    
    • 具体产品实现类
    /**
     * 惠普打印机(具体产品)
     */
    public class HpPrinter implements IPrinter {
    
        @Override
        public void print(){
            System.out.println("惠普打印机开始打印...");
        }
    
    }
    
    /**
     * 佳能打印机(具体产品)
     */
    public class CanonPrinter implements IPrinter {
    
        @Override
        public void print(){
            System.out.println("佳能打印机开始打印");
        }
    
    }
    
    • 抽象工厂方法,这里就是统一了打印机工厂创建产品的行为
    /**
     * 抽象工厂
     */
    public  abstract class PrinterFactory {
    
          abstract IPrinter createPrinter();
    
    }
    
    • 具体工厂类,实现具体产品的创建
    
    public class CannoPrinterFactory extends PrinterFactory {
    
        @Override
        IPrinter createPrinter() {
            return new CanonPrinter();
        }
    
    }
    
    public class HpPrinterFactory extends PrinterFactory {
        @Override
        IPrinter createPrinter() {
            return new HpPrinter();
        }
    }
    
    • 客户端调用
    public class Client {
    
            public static void main(String[] args){
                 //新增不同的产品,只需要提供不同的创建工厂实例         
                 PrinterFactory cannoPrinterFactory = new CannoPrinterFactory();
                 IPrinter cannoPrinter = cannoPrinterFactory.createPrinter();
                 cannoPrinter.print();
    
                 PrinterFactory hpPrintPrinterFactory = new HpPrinterFactory();
                 IPrinter hpPrinter = hpPrintPrinterFactory.createPrinter();
                 hpPrinter.print();
            }
    
    }
    

    上面的示例中,我们可以发现,虽然我们增加新的产品时候不需要像简单工厂那样去修改工厂类,但是却增加了相对应的产品工厂实现类和产品实现类(产品的实现类也可以放在工厂类中当做一个内部类去维护),造成了类的膨胀。在后面的抽象工厂模式中,引入了产品族的概念,可以比较下二者的适用范围

    使用典范

    • java.util.Collection
    //相当于是抽象工厂类
    public interface Collection<E> extends Iterable<E> {
        
    	//...省略
        
        /**
         * 这个就是其中一个工厂方法,需要由子类去实现
         * Returns an iterator over the elements in this collection.  There are no
         * guarantees concerning the order in which the elements are returned
         * (unless this collection is an instance of some class that provides a
         * guarantee).
         *
         * @return an <tt>Iterator</tt> over the elements in this collection
         */
        Iterator<E> iterator();
        
    	//...省略
    }
    

    其中的ArrayList就是一个抽象工厂类的实现类,里面实现了 iterator()工厂方法,其中返回的Itr() 返回的就是一个具体的产品,Iterator接口就是抽象产品接口

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    	//...省略
    	
        /**
         * 对Collection中定义的工厂方法实现,返回一个Iterator产品接口的实现类对象
         * Returns an iterator over the elements in this list in proper sequence.
         *
         * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
         *
         * @return an iterator over the elements in this list in proper sequence
         */
        public Iterator<E> iterator() {
            return new Itr();
        }
    
        /**
         * Iterator 就是一个抽象产品接口,Itr 就是具体的产品类
         * An optimized version of AbstractList.Itr
         */
        private class Itr implements Iterator<E> {
          // ...省略
        }
       // ...省略
    }
    
    public static void main(String[] args) {
       Collection fatory = new ArrayList();//具体工厂实例
       Iterator iterator = fatory.iterator();//返回具体产品实例
      // ...接下来就可以是用iterator这个产品的功能,如循环遍历
    }
    
    • logback日志框架中的LoggerFactory

    一般的日志框架不会直接使用,而是使用门面模式的slf4j,它提供了一个抽象工厂接口org.slf4j.ILoggerFactory和一个抽象产品接口org.slf4j.Logger,而具体的日志框架随用户自行引入

    package org.slf4j;
    //抽象产品工厂
    public interface ILoggerFactory {
        //抽象工厂方法
        public Logger getLogger(String name);
    }
    
    //抽象产品接口
    public interface Logger {
    	//省略	...
    }
    

    我们一般在项目中,都会以如下的方式去获得日志对象

    final static Logger logger = LoggerFactory.getLogger(Wombat.class);
    

    查看LoggerFactory类,可以追溯到这样一个获得日志产品对象的方法

    /**
     * Return a logger named according to the name parameter using the
     * statically bound {@link ILoggerFactory} instance.
     * 
     * @param name
     *            The name of the logger.
     * @return logger
     */
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();//这里是获得了具体工厂
        return iLoggerFactory.getLogger(name);//调用工厂获得具体日志产品对象
    }
    

    我们在代码中都是调用门面模式slf4j的api,隔离了具体的日志框架,这给我们在替换日志组件时候达到了无缝切换的效果,但有一个大大的前提是这些日志组件都是实现了slf4j定义的抽象产品接口和抽象工厂接口规范

    重点关注getILoggerFactory,下面的英文注释也说得很明白,在编译时就会绑定日志组件的工厂实例并返回

    /**
     * Return the {@link ILoggerFactory} instance in use.
     * <p/>
     * <p/>
     * ILoggerFactory instance is bound with this class at compile time.
     * 
     * @return the ILoggerFactory instance in use
     */
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    performInitialization();
                }
            }
        }
        switch (INITIALIZATION_STATE) {
        case SUCCESSFUL_INITIALIZATION:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case NOP_FALLBACK_INITIALIZATION:
            return NOP_FALLBACK_FACTORY;
        case FAILED_INITIALIZATION:
            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
        case ONGOING_INITIALIZATION:
            // support re-entrant behavior.
            // See also http://jira.qos.ch/browse/SLF4J-97
            return SUBST_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
    }
    

    查看ILoggerFactory接口发现,有三个ILoggerFactory实现类

    其中Logback日志框架的工厂如下:

    //具体工厂实现类
    public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {
    ...
        //具体工厂方法
        @Override
        public final Logger getLogger(final String name) {
        	...
        }
    ...
    }
    

    因此当引入了logback日志组件并配置日志参数后,调用getILoggerFactory方法返回的就是logback的工厂实例

  • 相关阅读:
    SpringMVC组件解析
    SpringMVC简介
    spring集成web环境
    Spring基于注解的事务控制
    Spring基于XML声明式事务控制
    Spring事务控制&编程式事务控制三大对象
    基于注解的AOP开发
    基于xml的AOP开发
    python字符串操作
    赋值、深拷贝、浅拷贝
  • 原文地址:https://www.cnblogs.com/DiDi516/p/12733058.html
Copyright © 2011-2022 走看看