什么是简单工厂模式
简单工厂模式不是GoF23种设计模式之一,简单工厂模式通过一个工厂类来决定具体应该实例化哪一个具体的类。
结构
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
UML类图
代码理解
抽象产品代码
public abstract class Coffee {
public void withSugar() {
System.out.println("加糖");
}
public void withMilk() {
System.out.println("加奶");
}
public abstract String getName();
}
具体产品代码
public class LatteCoffee extends Coffee{
@Override
public String getName(){
return "拿铁咖啡";
}
}
public class MochaCoffee extends Coffee{
@Override
public String getName(){
return "摩卡咖啡";
}
}
具体工厂代码
public class CoffeeShop{
public Coffee orderCoffee(String type){
Coffee coffee = null;
switch (type){
case "Latte":
coffee = new LatteCoffee();
break;
case "Mocha":
coffee = new MochaCoffee();
break;
default:
System.out.println("没有你想要的咖啡");
break;
}
//加配料
if (coffee != null) {
coffee.withMilk();
coffee.withSugar();
}
return coffee;
}
}
客户端代码
public class Client {
public static void main(String[] args) {
CoffeeShop coffeeShop = new CoffeeShop();
Coffee coffee = coffeeShop.orderCoffee("Latte");
System.out.println(coffee.getName());
}
}
输出结果
优缺点
简单工厂模式的优点包括:
- 实现了对象的创建和使用的分离,客户端可以免除直接创建产品对象的职责,仅仅消费产品。
- 客户端无需知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,减少了使用者的记忆量。
缺点则包括:
- 工厂类的职责相对比较重,如果产品种类非常多,工厂方法会变得非常复杂。
- 当增加新产品时,需要修改工厂类,这违反了开闭原则(对扩展开放,对修改封闭)。
案例分析
JDK源码解析-Calendar类
在客户端使用Calendar.getInstance()实例化Calendar对象
public static Calendar getInstance(TimeZone zone,Locale aLocale)
{
return createCalendar(zone, aLocale);
}
调用getInstance()方法获得 createCalendar(zone, aLocale),具体实现如下:
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;
}
使用简单工厂模式的代码: