简单工厂模式
工厂模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。下面将陆续讲解几种设计模式。
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式,但不属于GOF23种设计模式
角色
-
简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象
-
抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
-
具体产品(ConcreteProduct):是简单工厂模式的创建目标。
代码案例
- 抽象产品
public abstract class Mobile {
/**
* 生产手机
*/
public abstract void produce();
}
- 具体产品 抽象产品具体实现
public class Iphone extends Mobile {
@Override
public void produce() {
System.out.println("apple iphone mobile");
}
}
public class Samsung extends Mobile{
@Override
public void produce() {
System.out.println("samsung Galaxy mobile");
}
}
- 简单工厂
public class SimpileFactory {
public static Mobile getMobile(String type){
if (type.equals("iphone")) {
return new Iphone();
}else if (type.equals("samsung")) {
return new Samsung();
}
return null;
}
public static Mobile getMobileForRelect(@SuppressWarnings("rawtypes") Class clazz) {
try {
return (Mobile)Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
- client 使用方
public class Client {
public static void main(String[] args) {
Mobile mobile = SimpileFactory.getMobile("iphone");
mobile.produce();
}
}
运行结果
apple iphone mobile
案例结构图
client通过传给工厂方法的手机类型来产生不同品牌的手机,这里我们还可以通过 反射的方式,传递具体的类型来获取手机对象实例。
public static Mobile getMobileForRelect(@SuppressWarnings("rawtypes") Class clazz) {
try {
return (Mobile)Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
- client 通过反射的方式获取对象
public static void main(String[] args) {
Mobile mobile2 = SimpileFactory.getMobileForRelect(Samsung.class);
mobile2.produce();
}
执行结果:
samsung Galaxy mobile
不管通过什么方式,我们只需要通过调用工厂方法就能获取到我们需要得到的对象。如果我们增加一种手机类型,假如我们增加华为手机,那么我们的工厂通过类型获取的对象的方式还是需要更改,这违背了“开闭原则”。 对于使用方来说的话,不管有多少个client,都无需修改代码,只需传入新的类型,即可获取新的对象。
优缺点
优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例;
- 客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品;
- 工厂和产品的职责区分明确客户端无需知道所创建具体产品的类名,只需知道参数即可。
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
缺点:
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
- 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
应用场景
- 对于产品种类相对较少的情况,考虑使用简单工厂模式。
- 使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
简单工厂模式的典型应用及源码分析
java.util
包下Calendar
类,他是一个抽象类,我们使用的时候,会通过 Calendar.getInstance()
获取Calendar
对象(子类对象),Calendar
抽象类的子类有 BuddhistCalendar
、JapaneseImperialCalendar
、GregorianCalendar
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
//...略
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;
}
}
截取了主要部分,Calendar
抽象类在这里既充当了工厂角色,也充当了抽象产品角色,具体产品为Calendar
子类充当。
✨✨ 欢迎🔔订阅个人的微信公众号 享及时博文更新
✨✨ 个人GitHub地址