简单工厂模式详解

简单工厂模式详解

原始社会自给自足(没有工厂)农耕社会小作坊(简单工厂,民间酒坊)
工厂流水线生产(工厂方法,自产自销)	现代产业链代工厂(抽象工厂,富士康)

简单工厂模式

定义

简单工厂模式是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF23中设计模式。

适用场景

适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关系。

缺点

工厂类的职责相对过重,不易于扩展过于复杂的产品结构

实践案例

以生产手机为例

public interface IPhone {
    //生产
    void produce();
}
public class ApplePhone implements IPhone {
    @Override
    public void produce() {
        System.out.println("开始生产Apple手机");
    }
}
public class HuaWeiPhone implements IPhone {
    @Override
    public void produce() {
        System.out.println("开始生产华为手机");
    }
}
public class XiaoMiPhone implements IPhone {
    @Override
    public void produce() {
        System.out.println("开始生产小米手机");
    }
}
public class PhoneFactory {
    public IPhone create(String brandName){
        IPhone phone = null;
        if (brandName.toLowerCase().equals("apple")) {
            phone = new ApplePhone();
        } else if (brandName.toLowerCase().equals("huawei")) {
            phone = new HuaWeiPhone();
        } else if (brandName.toLowerCase().equals("xiaomi")) {
            phone = new XiaoMiPhone();
        }
        return phone;
    }
}
public class PhoneFactoryTest {
    public static void main(String[] args) {
        PhoneFactory phoneFactory = new PhoneFactory();
        IPhone phone = phoneFactory.create("xiaomi");
        phone.produce();
    }
}

在这里插入图片描述

客户端调用简单,但手机业务扩展时,需要对简单工厂中create()方法修改逻辑,不符合开闭原则

因此,我们对简单工厂还可以继续优化,可加入反射技术:

public class PhoneFactory {
    public IPhone create(String className){
        IPhone phone = null;
        try {
            if (className != null && !className.trim().equals("")) {
                phone = (IPhone) Class.forName(className).newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return phone;
    }
}
public class PhoneFactoryTest {
    public static void main(String[] args) {
        PhoneFactory phoneFactory = new PhoneFactory();
        IPhone phone = phoneFactory.create("com.design.pattern.simple.factory.phone.XiaoMiPhone");
        phone.produce();
    }
}

优化之后,手机业务扩展后,不需要修改简单工厂类中的方法。但是有个问题,方法参数的字符串,可控性有待提高,而且还需要强制转型,所以再次优化:

public class PhoneFactory {
    public IPhone create(Class <? extends IPhone> clazz){
        IPhone phone = null;
        try {
            if (clazz != null) {
                phone = clazz.newInstance();
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return phone;
    }
}
public class PhoneFactoryTest {
    public static void main(String[] args) {
        PhoneFactory phoneFactory = new PhoneFactory();
        IPhone phone = phoneFactory.create(XiaoMiPhone.class);
        phone.produce();
    }
}

在这里插入图片描述

简单工厂在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) {
    Logger logger = getLogger(clazz.getName());
    if (DETECT_LOGGER_NAME_MISMATCH) {
        Class<?> autoComputedCallingClass = Util.getCallingClass();
        if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
            Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
            Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
        }
    }

    return logger;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值