Java设计模式之——简单工厂

导语

在日常开发中,一般而言是很少涉及到设计模式的,或者说很多时候就算接触到了设计模式,很多人或许却并不知道自己遇见了设计模式。所以在这次这个系列的文章中,还是想简单的介绍一下一些设计模式,以及这些设计模式的概念、适用场景等等。其中只用少量的文字来叙述,大部分还是用代码来展示,因为个人觉得这样其实才是最直接的。对于在文章中,可能还涉及一些jdk源码或一些框架中应用了哪些设计模式,进行一些简单的概述以及代码的展示。

 

一、简单工厂定义和类型

定义:由一个工厂对象决定创建出哪一种产品类的实例。

类型:创建型(其实是不属于GOF23种设计模式中的)

 

二、简单工厂的使用场景与优缺点

适用场景:

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

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

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

三、简单工厂模式UML图

代码具体实现如下:

1.首先定义一个抽象冰箱类:

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

2.再定义两个相关的品牌冰箱的实现类:

public class GeLiFridge extends Fridge {
    @Override
    public void produce() {
        System.out.println("-----生产格力空调-----");
    }
}
public class PanasonicFridge extends Fridge {
    @Override
    public void produce() {
        System.out.println("-----生产松下冰箱-----");
    }
}

3.创建冰箱的工厂类

这里在冰箱工厂类中使用两种方式去实现,一种是使用传入参数类型,一种是传入具体要创建的类(在一定程度上满足开闭原则,因为在新增需要创建类的时候,不需要修改工厂类)。

public class FridgeFactory {

    // 2.传入具体需要创建的类
    public Fridge getFridge(Class c) {
        Fridge fridge = null;

        try {
            fridge = (Fridge) Class.forName(c.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return fridge;
    }

    // 1.传入参数类型
    public Fridge getFridge(String type) {
        if("geli".equals(type)) {
            return new GeLiFridge();
        }else if ("panasonic".equals(type)) {
            return new PanasonicFridge();
        }

        return null;
    }
}

4.测试类

public class MainTest {
    public static void main(String[] args) {

        // 2.传入具体需要创建的类
        FridgeFactory fridgeFactory =new FridgeFactory();
        Fridge fridge = fridgeFactory.getFridge(GeLiFridge.class);
        if (fridge == null) {
            return;
        }
        fridge.produce();

        // 1.传入参数类型
        FridgeFactory ff =new FridgeFactory();
        Fridge f = ff.getFridge("geli");
        if (f == null) {
            return;
        }
        f.produce();

    }
}

测试结果:

四、简单工厂方法在JDK源码中的体现

在JDK中有体现这样的简单工厂这样的设计代码,先在IDEA中找到Calendar类(使用Ctrl+Shift+N),然后找到这个类中的getInstance(TimeZone zone)这个方法(Ctrl + F12)。

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

从上面代码中,可以得知这个方法是一个静态方法,在这个方法里调用了createCalendar(TimeZone.getDefault(), 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 (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;
    }

上面这段代码中,在最后判断if (cal == null)这个代码块中,有对国家语言进行判断。相比较上面自己创建的工厂类中的第一种类型,也是对传入的类型进行一个简单的判断,只是这里的createCalendar方法是静态的,因为这里已经满足了需求,并不需要考虑它的扩展性的。接下来我们也看下这个类的UML图:

从上面的UML类图中,可以看出Calendar实现了三个接口,还有集成Calendar这个类的两个子类。而Calendar自身是一个抽象类,在上图中的符号也能看出来。

 

 

版权声明:尊重博主原创文章,转载请注明出处:https://blog.csdn.net/zfy163520

 

发布了41 篇原创文章 · 获赞 8 · 访问量 4274

猜你喜欢

转载自blog.csdn.net/zfy163520/article/details/90603584