《Java设计模式_1》设计模式规则及简单工厂模式


如未作特殊说明,本文均为原创,转发请注明出处。

文章目录

    • 如未作特殊说明,本文均为原创,转发请注明出处。
  • 前言
  • 软件设计七大原则
  • GOF外的简单工厂模式
    • 定义
    • 类型
    • 使用场景
    • 优点
    • 缺点
    • Coding
      • 第一种简单工厂方案
      • 第二种简单工厂方案
  • 从源码种发现简单工厂模式
  • 参考文献

前言

​ 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

​ 设计模式就像那一则则寓言故事一样,事经过前人的反复摸索和总结出来的精华。在JAVA语言中目的是为了让程序更加具有扩展性、健壮性、更加的通俗易通。


软件设计七大原则

  1. 开闭原则
  2. 依赖倒置原则
  3. 单一职责原则
  4. 接口隔离原则
  5. 迪米特原则
  6. 里氏替换法则
  7. 合成复用法则

这里不一一详细介绍,有兴趣的可以深入研究一下各种原则的优点。

大部分都是为了提高代码的复用性和健壮性而提出的!!!


GOF外的简单工厂模式

​ 通过标题可以看出,该模式是不在GOF 23种设计模式之中的

定义

​ 有一个冲对象决定创建出哪一种产品类的实例

类型

​ 创建型,但不属于GOF 23种设计模式

使用场景

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

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

优点

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

缺点

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

Coding

​ 所有代码都在我的GitHub

设计模式代码托管

第一种简单工厂方案

​ 使用对字符串的比较来确定实体类的具体实现

    /**
     * v1:
     * 简单的判断方式来进行初始化类
     */
    public void videoFactory(String videoName) {
        if ("java".equalsIgnoreCase(videoName)) {
           new JavaVideo().production();
       } else if ("FE".equalsIgnoreCase(videoName)) {
            new FEVideo().production();
       }else {
            System.out.println("没有该课程啊");
        }
    }

《Java设计模式_1》设计模式规则及简单工厂模式_第1张图片

第二种简单工厂方案

​ 利用Java的反射机制,完成实体类的实现。此种方法更加的灵活,且完美的符合开闭原则。在后续功能的增加时,只需要添加相应的继承类就可以了,不需要对工厂类的调整。

    /**
     * v2:
     * 利用反射机制替代判断来创建实体类。并且完美的解决了之后如果课程增加需要修改工厂类的麻烦。
     *
     * @param clazz
     */
    public Video videoFactoryV2(Class clazz) {
        Video video = null;
        // 使用反射 创建实体类
        try {
            video = (Video) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return video;
    }

从源码种发现简单工厂模式

​ 在Java 源码中 Calendar类中的getInstance()方法

    public static Calendar getInstance(TimeZone zone)
    {
        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
    }


 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;

     // 这里用来判断语言,则使用上述简单工厂的第一种方法。
        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 (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;
    }

《Java设计模式_1》设计模式规则及简单工厂模式_第2张图片

这里可以看到 Calendar是一个抽象类。

第二种使用反射机制的源码则是JAVA JDBC中驱动加载时应用到了简单工厂模式。

Class.forName("com.mysql.jdbc.Driver");

//加载驱动在mysqk 驱动类中又一个静态代码块(会在该类加载时执行该代码块) 
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}
// 如果不存在则注册!!! addIfAbsent
public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }

参考文献

慕课网,java设计模式精讲 Debug 方式+内存分析

《Head First 设计模式》

后面所有设计模式如未做特殊说明将都是基于以上文献。所有内容仅供本人学习之用。多谢!!!

你可能感兴趣的:(Java,设计模式,Java基础,设计模式)