zoukankan      html  css  js  c++  java
  • Java设计模式(三)简单工厂模式

    定义与类型

    • 定义:由一个工厂对象决定创建出哪一种产品类的实例
    • 类型:创建型,但不属于GOF23种设计模式

    适用场景

    • 工厂类负责创建的对象比较少
    • 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心

    优点

    只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节

    缺点

    工厂类的职责相对过重,增加新的产品,需要修改工厂类的判断逻辑,违背开闭原则

    Coding

    创建一个抽象产品类

    public abstract class Video {
        public abstract void produce();
    }
    

    产品实现类

    public class JavaVideo extends Video {
        @Override
        public void produce() {
            System.out.println("录制Java课程");
        }
    }
    public class PythonVideo extends Video {
        @Override
        public void produce() {
            System.out.println("录制Python视频");
        }
    }
    

    创建产品对应的简单工厂,通过产品类型来创建产品,应用方无需知道创建产品的细节

    public class VideoFactory {
    
        public Video getVideo(String type) {
            if ("java".equalsIgnoreCase(type)) {
                return new JavaVideo();
            } else if ("python".equalsIgnoreCase(type)) {
                return new PythonVideo();
            } else {
                return null;
            }
        }
    }
    

    测试类

    public class Test {
        public static void main(String[] args) {
            VideoFactory videoFactory = new VideoFactory();
            Video video = videoFactory.getVideo("Java");
            video.produce();
        }
    }
    

    控制台输出

    录制Java课程
    

    如果增加产品,我们不仅需要修改产品对应的产品类,还需要修改工厂类,违反了开闭原则。

    我们可以通过反射来优化下我们的工厂类

    public class VideoFactory {
    
        public Video getVideo(Class<? extends Video> clazz) {
            try {
                return clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    这样一来,添加产品的时候不用再修改我们的工厂类,而是直接添加产品即可。

    最终的UML类图

    源码解析

    JDK源码

    在JDK中,使用简单工厂模式的例子如java.util.Calendar,一组getInstance的重载方法,提供了创建Calendar产品的简单工厂方法。

    public static Calendar getInstance()
    public static Calendar getInstance(TimeZone zone)
    public static Calendar getInstance(Locale aLocale)
    public static Calendar getInstance(TimeZone zone,Locale aLocale)
    

    核心方法为

    private static Calendar createCalendar(TimeZone zone,Locale aLocale)
    

    源码较长,不贴了,有兴趣的可以去看下源码。

    Calendar的UML类图如下

    Logback源码

    logback类中的简单工厂模式主要体现在ch.qos.logback.classic.LoggerContext#getLogger(String)

    @Override
    public final Logger getLogger(final String name) {
    
        if (name == null) {
            throw new IllegalArgumentException("name argument cannot be null");
        }
    
        // 判断log类型返回root节点的logger
        if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            return root;
        }
    
        int i = 0;
        Logger logger = root;
    
        // 如果缓存中已经存在的指定的logger,直接返回childLogger
        Logger childLogger = (Logger) loggerCache.get(name);
        // if we have the child, then let us return it without wasting time
        if (childLogger != null) {
            return childLogger;
        }
    
        // 以下是创建logger的逻辑
        String childName;
        while (true) {
            int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
            if (h == -1) {
                childName = name;
            } else {
                childName = name.substring(0, h);
            }
            // move i left of the last point
            i = h + 1;
            synchronized (logger) {
                childLogger = logger.getChildByName(childName);
                if (childLogger == null) {
                    childLogger = logger.createChildByName(childName);
                    loggerCache.put(childName, childLogger);
                    incSize();
                }
            }
            logger = childLogger;
            if (h == -1) {
                return childLogger;
            }
        }
    }
    

    是一个典型的简单工厂方法

  • 相关阅读:
    Java线程池,你了解多少?
    Git-常用命令
    CentOS6.6 编译Redis报错:"Newer version of jemalloc required"
    IDEA 常用快捷键
    Java并发编程(4)--生产者与消费者模式介绍
    CSS样式----浮动(图文详解)
    实现键盘记录的e.Whick和keyCode,兼容FireFox和IE
    如何用Fireworks制作经典的扫光字GIF动画
    asp.net中label控件设置字体大小
    [HttpException (0x80004005): 应用程序已预编译,因此不允许使用目录“/App_Code/”。]
  • 原文地址:https://www.cnblogs.com/gcdd/p/12292126.html
Copyright © 2011-2022 走看看