设计模式2.0——工厂模式三剑客——简单工厂模式

设计模式2.0-工厂模式

先来回忆一下设计原则:

设计原则解释
开闭原则对扩展开放,对修改关闭。
依赖倒置原则通过抽象使各个类或者模块不相互影响,实现松耦合。
单一职责原则一个类、接口、方法只做一件事
接口隔离原则尽量保证接口的纯洁性,客户端不应该依赖不需要的接口。
迪米特法则又叫最少知道原则,一个类对其所依赖的类知道得越少越好。
里氏替换原则子类可以扩展父类的功能但不能改变父类原有的功能。
合成复用原则尽量使用对象组合、聚合,而不使用继承关系达到代码复用的目的。

工厂模式详解

工厂模式的历史由来

在现实生活中我们都知道,原始社会自给自足(没有工厂)、农耕社会小作坊(简单工 厂,民间酒坊)、工业革命流水线(工厂方法,自产自销)、现代产业链代工厂(抽象工厂, 富士康)

简单工厂模式

简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于 GOF,23 种设计模式简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。接下来我们来看代码

我们可以定义一个课程标准 ICar接口:

 

/**
 * 汽车接口
 */
public interface ICar {
    void run();
}
/**
 * 奥迪类
 */
public class AudiCar implements ICar {
    @Override
    public void run() {
        System.out.println("奥迪跑起来了");
    }
}
public static void main(String[] args) {
        ICar iCar=new AudiCar();
        iCar.run();
}

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

/**
 * 凯迪拉克类
 */
public class CadillacCar implements ICar {
    @Override
    public void run() {
        System.out.println("凯迪拉克跑起来了");
    }
}

创建工厂类SimpleFactory,下面给出了三种创建工厂方法

 /**
     * 创建实例
     * @param type
     * @return
     */
    public ICar create(String type){
      if(StringUtils.isEmpty(type)){
         return null;
      }
      if("Audi".equals(type)){
          return new AudiCar();
      }else if("Cadillac".equals(type)){
         return new CadillacCar();
      }else {
          return null;
      }
    }
/**
     * 通过反射创建,不修改代码逻辑
     * @param className
     * @return
     */
    public ICar createByclazz(String className){
        try {
            if (!(null == className || "".equals(className))) {
                return (ICar) Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
/**
     * 通过类实例化,方法参数是字符串,可控性有待提升,而且还需要强制转型
     * @param clazz
     * @return
     */
    public ICar create(Class<? extends ICar> clazz){
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

客户端调用代码

/**
 * 简单工厂模式测试类
 * 优点:把创建代码封装到工厂里,调用者感应不到,只需要传入响应的类型即可
 * 缺点:不符合开闭原则,没增加一个产品都要修改工厂代码,不易于扩展
 */
public class SimpleFactoryTest {

    public static void main(String[] args) {
        SimpleFactory simpleFactory=new SimpleFactory();
        ICar iCar= simpleFactory.create("Audi");
        iCar.run();

        //通过反射调用
        ICar iCar1=simpleFactory.createByclazz("com.design.pattern.common.AudiCar");
        iCar1.run();

        ICar iCar2=simpleFactory.create(AudiCar.class);
        iCar2.run();
    }
}

我们来看一下类图:

简单工厂模式在 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) {
        // 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;
}

还有一个大家经常使用的 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());
}

简单工厂也有它的缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值