彻底说透简单工厂那些你没有关注过的细节

简介: 接下来看代码,还是以创建一门网络课程为例。假设有Java架构、大数据、人工智能等课程,已经形成了一个生态。我们可以定义一个课程标准ICourse接口。

本文节选自《设计模式就该这样学》

1 使用简单工厂模式封装产品创建细节

接下来看代码,还是以创建一门网络课程为例。假设有Java架构、大数据、人工智能等课程,已经形成了一个生态。我们可以定义一个课程标准ICourse接口。

public interface ICourse {
    /** 录制视频 */
    public void record();
}

创建一个Java课程的实现类JavaCourse。

public class JavaCourse implements ICourse {
    public void record() {
        System.out.println("录制Java课程");
    }
}

客户端调用代码如下。

public static void main(String[] args) {
    ICourse course = new JavaCourse();
    course.record();
}

由上面代码可知,父类ICourse指向子类JavaCourse的引用,应用层代码需要依赖JavaCourse。如果业务扩展,则继续增加PythonCourse,甚至更多,那么客户端的依赖会变得越来越臃肿。因此,我们要想办法把这种依赖减弱,把创建细节隐藏。虽然在目前的代码中,创建对象的过程并不复杂,但从代码设计角度来讲不易于扩展。因此,用简单工厂模式对代码进行优化。首先增加课程PythonCourse类。

public class PythonCourse implements ICourse {
    public void record() {
        System.out.println("录制Python课程");
    }
}

然后创建CourseFactory工厂类。

public class CourseFactory {
    public ICourse create(String name){
        if("java".equals(name)){
            return new JavaCourse();
        }else if("python".equals(name)){
            return new PythonCourse();
        }else {
            return null;
        }
    }
}

最后修改客户端调用代码。

public class SimpleFactoryTest {
    public static void main(String[] args) {
        CourseFactory factory = new CourseFactory();
        factory.create("java");
    }
}

当然,为了调用方便,可将CourseFactory的create()方法改为静态方法,其类图如下图所示。


20211110140108895.png

客户端调用虽然简单了,但如果业务继续扩展,要增加前端课程,则工厂中的create()方法就要随着产品链的丰富每次都要修改代码逻辑,这不符合开闭原则。因此,我们可以采用反射技术继续对简单工厂模式进行优化,代码如下。

public class CourseFactory {
    public ICourse create(String className){
        try {
            if (!(null == className || "".equals(className))) {
                return (ICourse) Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

客户端调用代码修改如下。

public static void main(String[] args) {
        CourseFactory factory = new CourseFactory();
        ICourse course = factory.create("com.gupaoedu.vip.pattern.factory.simplefactory.JavaCourse");
        course.record();
}

优化之后,产品不断丰富,不需要修改CourseFactory中的代码。但问题是,方法参数是字符串,可控性有待提升,而且还需要强制转型。继续修改代码。

public ICourse create(Class<? extends ICourse> clazz){
    try {
        if (null != clazz) {
            return clazz.newInstance();
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return null;
}

优化客户端测试代码。

public static void main(String[] args) {
    CourseFactory factory = new CourseFactory();
    ICourse course = factory.create(JavaCourse.class);
    course.record();
}

最后来看如下图所示的类图。

20211110140109317.png

2 简单工厂模式在JDK源码中的应用

简单工厂模式在JDK源码中无处不在,例如Calendar类,看Calendar.getInstance()方法。下面打开的是Calendar的具体创建类。

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) {
        }
    }
    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 (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;
}

3 简单工厂模式在Logback源码中的应用

在大家经常使用的Logback中,可以看到LoggerFactory中有多个重载的方法getLogger()。

public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
}
public static Logger getLogger(Class clazz) {
    return getLogger(clazz.getName());
}


【推荐】Tom弹架构:30个设计模式真实案例(附源码),挑战年薪60W不是梦


本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。

相关文章
|
8天前
|
设计模式 API 数据安全/隐私保护
探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密
外观模式是一种关键的设计模式,旨在通过提供一个简洁的接口来简化复杂子系统的访问。其核心价值在于将复杂的内部实现细节封装起来,仅通过一个统一的外观对象与客户端交互,从而降低了系统的使用难度和耦合度。在软件开发中,外观模式的重要性不言而喻。它不仅能够提高代码的可读性、可维护性和可扩展性,还能促进团队间的协作和沟通。此外,随着业务需求和技术的发展,外观模式能够适应变化,通过修改外观对象来灵活调整客户端与子系统之间的交互方式。总之,外观模式在软件设计中扮演着举足轻重的角色,是构建高效、稳定且易于维护的软件系统的关键
78 1
探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密
|
7月前
|
设计模式 Java 数据库连接
解锁设计模式的神秘面纱:编写无懈可击的代码之建造者设计模式
解锁设计模式的神秘面纱:编写无懈可击的代码之建造者设计模式
35 0
|
8天前
|
编译器
深挖编程:揭秘隐藏基类方法的奥秘
深挖编程:揭秘隐藏基类方法的奥秘
17 3
|
8天前
|
设计模式 算法 Java
二十三种设计模式全面解析-当你的代码需要多种算法时,策略模式是你的救星!
二十三种设计模式全面解析-当你的代码需要多种算法时,策略模式是你的救星!
|
8天前
|
设计模式 API 数据格式
二十三种设计模式全面解析-适配器模式:代码的奇迹之桥,连接你的世界!
二十三种设计模式全面解析-适配器模式:代码的奇迹之桥,连接你的世界!
|
8天前
|
设计模式 Java
根据真实业务场景去实现一下设计模式中的装饰者模式
根据真实业务场景去实现一下设计模式中的装饰者模式
19 0
|
9月前
|
设计模式 数据安全/隐私保护
这才是责任链模式的优雅使用方式
首先创建一个实体类Member。
66 0
|
11月前
|
设计模式 Java
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
158 0
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
|
11月前
《重构2》第十二章-继承
《重构2》第十二章-继承
96 0
|
存储 编译器 C++
C++继承和多态核心重点知识刨析,一文必拿下
C++继承和多态核心重点知识刨析,一文必拿下
C++继承和多态核心重点知识刨析,一文必拿下

热门文章

最新文章