zoukankan      html  css  js  c++  java
  • Java设计模式学习——简单工厂

    一. 定义与类型

    定义:有工程对象决定创建出哪一种产品类的实例

    类型:创建型,但不属于GOF23中设计模式

    二. 适用场景

    工厂类负责创建的对象比较少

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

    三. 优点与缺点

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

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

    四. coding

    /**
     * @program: designModel
     * @description: 视频类
     * @author: YuKai Fan
     * @create: 2018-11-13 16:46
     **/
    public abstract class Video {
        public abstract void product();
    }
    /**
     * @program: designModel
     * @description: java视频类
     * @author: YuKai Fan
     * @create: 2018-11-13 16:47
     **/
    public class JavaVideo extends Video {
        public void product() {
            System.out.println("录制java课程视频");
        }
    }
    /**
     * @program: designModel
     * @description: Python视频类
     * @author: YuKai Fan
     * @create: 2018-11-13 16:48
     **/
    public class PythonVideo extends Video{
        public void product() {
            System.out.println("录制Python课程视频");
        }
    }
    /**
     * @program: designModel
     * @description:
     * @author: YuKai Fan
     * @create: 2018-11-13 16:48
     **/
    public class Test {
        public static void main(String[] args) {
            /*Video video = new JavaVideo();
            video.product();*/
            VideoFactory videoFactory = new VideoFactory();
            Video java = videoFactory.getVideo("java");
            if (java == null) {
                return;
            }
            java.product();
        }
    }

    这样,应用层(客户端)只需要传入需要的类型,就可以得到相应的类型视频,不知道创建的细节,UML类图为

    但是,如果要新增加一个课程的话,就必须在原有的基础上修改代码,这样违背了设计原则的开闭原则

    可以对上面的代码进行一定的改进,通过反射的方法来完成类型的选择

    /**
     * @program: designModel
     * @description:
     * @author: YuKai Fan
     * @create: 2018-11-13 16:50
     **/
    public class VideoFactory {
        public Video getVideo(Class c) {
            Video video = null;
            try {
                video = (Video) Class.forName(c.getName()).newInstance();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return video;
        }
    
        /*public Video getVideo(String type) {
    
            if ("java".equalsIgnoreCase(type)) {
                return new JavaVideo();
    
            } else if ("python".equalsIgnoreCase(type)) {
                return new PythonVideo();
    
            }
            return null;
        }*/
    }
    /**
     * @program: designModel
     * @description:
     * @author: YuKai Fan
     * @create: 2018-11-13 16:48
     **/
    public class Test {
        public static void main(String[] args) {
            /*Video video = new JavaVideo();
            video.product();*/
            /*VideoFactory videoFactory = new VideoFactory();
            Video java = videoFactory.getVideo("java");
            if (java == null) {
                return;
            }
            java.product();*/
            VideoFactory videoFactory = new VideoFactory();
            Video java = videoFactory.getVideo(JavaVideo.class);
            if (java == null) {
                return;
            }
            java.product();
        }
    }

    这样的好处是,应用层(客户端)直接传入对应的视频类class即可,不需要修改工厂类的代码

    五. 源码分析 jdk源码解析

    在jdk中使用简单工厂的体现:

    1.calender.java中的getInstance方法中的createCalender方法

    private static Calendar createCalendar(TimeZone zone,
                                               Locale aLocale)
        {
            CalendarProvider provider =
                LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                     .getCalendarProvider();
            if (provider != null) {
                try {
                    return provider.getInstance(zone, aLocale);
                } catch (IllegalArgumentException iae) {
                    // fall back to the default instantiation
                }
            }
    
            Calendar cal = null;
            
    //这里使用的就是简单工厂模式,switch-case判断返回相应的国家日期类型
    if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); if (caltype != null) { switch (caltype) { case "buddhist": cal = new BuddhistCalendar(zone, aLocale); break; case "japanese": cal = new JapaneseImperialCalendar(zone, aLocale); break; case "gregory": cal = new GregorianCalendar(zone, aLocale); break; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned.

           //这里使用的就是简单工厂模式,if-else判断返回相应的国家日期类型
    if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }

    这个类的UML为:

    jdbc中的加载驱动,获取连接,也是用的简单工厂模式

  • 相关阅读:
    【python】mongo删除数据
    【linux】复制文件夹中文件,排除部分文件
    【mysql】datetime时间比较
    【python】del
    【linux】shell代码,获取当前路径,创建文件夹
    【python】打印函数调用栈
    【linux】复制文件夹内容到另一个文件夹
    【gearman】gearmand -d 无反应解决
    【python】异步编程twisted
    AndrewNG Deep learning课程笔记
  • 原文地址:https://www.cnblogs.com/FanJava/p/9953404.html
Copyright © 2011-2022 走看看