工厂模式介绍
工厂模式(Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式。其在父类中提供⼀个创建对象的发放, 允许子类决定实例化对象的类型。
分类
简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern)。
工厂方法(Factory Method)模式,又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式。
抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。
简单工厂模式
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法模式(Static Factory Method Pattern),在简单工厂模式中,可根据参数的不同返回不同的实例。简单工厂模式专门定义一个类来负责创建其他类的实力,被创建类的实例通常都具有共同的父类,或者实现相同的接口。
基本角色
Product(抽象产品):它是工厂类所创建对象的父类,封装了所有产品对象共有的方法。
ConcreteProduct(具体产品):继承抽象产品角色,它是简单工厂模式所创建目标,工厂类返回的对象都是该某一具体产品角色。
Factory (工厂) :是简单工厂模式的核心,它负责实现创建所有具体产品的实例的内部逻辑,工厂类可以被外界直接调用,创建所需的产品对象。
代码
public class SimpleFactory {
public static Product createProduct(String type) throws Exception {
if (null != type && type.equals("A"))
return new ProductA();
else if (null != type && type.equals("B")) {
return new ProductB();
}else {
throw new Exception("type error.");
}
}
public static void main(String[] args) throws Exception {
Product product = SimpleFactory.createProduct("A");
product.print();
}
}
//抽象类
abstract class Product {
public abstract void print();
}
class ProductA extends Product {
@Override
public void print() {
System.out.println("ProductA");
}
}
class ProductB extends Product {
@Override
public void print() {
System.out.println("ProductB");
}
}
简单工厂模式的优点
- 将对象的创建与使用分离,将对象的创建交给工厂类负责。
- 客户端无需知道所创建的具体产品类的类名,只要知道具体产品类所对应的参数即可,然后通过工厂类获取。
简单工厂模式的缺点
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦有问题会导致整个系统受影响。
- 如果引入新的具体产品,就会导致去修改工厂类的逻辑,不符合“开闭原则”。
- 不适合产品类(Product)过多的情况。
工厂方法模式
工厂方法模式不再提供一个工厂类来创建所有的产品对象,而是根据不同的产品来提供不同的工厂类。
基本角色
Product(抽象产品) :定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
ConcreteProduct(具体产品) :它实现了抽象产品接口,某种类型的产品由专门的具体工厂创建,具体工厂和具体产品有一一对应关系。
Factory(抽象工厂):在抽象工厂类中,声明了工厂方法用于返回一个产品,抽象工厂是工厂模式的核心,所有对象的工厂类都必须实现该接口。
ConcreteFactory(具体工厂):它是抽象工厂的子类,实现了抽象工厂中的方法,并由客户端调用返回一个具体的产品。
代码
public class MethodFactory {
public static void main(String[] args) throws Exception {
Factory factorya = new FactoryA();
Product producta = factorya.createProduct();
producta.print();
Factory factoryb = new FactoryB();
Product productb = factoryb.createProduct();
productb.print();
}
}
//抽象工厂
abstract class Factory {
public abstract Product createProduct();
}
//具体工厂A
class FactoryA extends Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
//具体工厂B
class FactoryB extends Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
//抽象产品
abstract class Product {
public abstract void print();
}
//具体产品A
class ProductA extends Product {
@Override
public void print() {
System.out.println("ProductA");
}
}
//具体产品B
class ProductB extends Product {
@Override
public void print() {
System.out.println("ProductB");
}
}
工厂方法模式的优点
扩展性好,符合了开闭原则,新增一种产品时,只需增加对应的产品类和对应的工厂子类即可。符合单一职责原则,每个工厂只负责一种产品,而不是由一个工厂去生成所有商品。
工厂方法模式的缺点
当我们新增产品时,还需要提供对应的工厂类,系统中类的个数将会成倍增加,相当于增加了系统的复杂性。
抽象工厂模式
抽象工厂模式有点像是工厂方法模式的升级版。它打破了工厂与产品一一对应的关系。抽象工厂模式只是工厂模式的一个拓展,抽象工厂模式如果只有一个产品体系的话就会退化成工厂模式。
工厂方法模式针对的某一种产品,而抽象工厂模式可以针对多种产品。
基本角色
Product(抽象产品) :定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
ConcreteProduct(具体产品) :它实现了抽象产品接口,某种类型的产品由专门的具体工厂创建,具体工厂和具体产品有一一对应关系。
Factory(抽象工厂):在抽象工厂类中,声明了工厂方法用于返回一个产品,抽象工厂是工厂模式的核心,所有对象的工厂类都必须实现该接口。
ConcreteFactory(具体工厂):它是抽象工厂的子类,实现了抽象工厂中的方法,并由客户端调用返回一个具体的产品。
代码
public class AbstractFactory {
public static void main(String[] args) throws Exception {
Factory factorya = new FactoryA();
Computer computerLenovo = factorya.createComputer();
computerLenovo.print();
Factory factoryb = new FactoryA();
Phone phoneHuawei = factorya.createPhone();
phoneHuawei.print();
Factory factoryc = new FactoryB();
Computer computerDell = factoryc.createComputer();
computerDell.print();
Factory factoryd = new FactoryB();
Phone phoneMi = factoryc.createPhone();
phoneMi.print();
}
}
//抽象工厂
abstract class Factory {
public abstract Computer createComputer();
public abstract Phone createPhone();
}
//具体工厂A
class FactoryA extends Factory {
@Override
public Computer createComputer() {
return new Lenovo();
}
@Override
public Phone createPhone() {
return new Huawei();
}
}
//具体工厂B
class FactoryB extends Factory {
@Override
public Computer createComputer() {
return new Dell();
}
@Override
public Phone createPhone() {
return new Mi();
}
}
//抽象产品电脑
abstract class Computer {
public abstract void print();
}
//具体产品Lenovo
class Lenovo extends Computer {
@Override
public void print() {
System.out.println("Lenovo");
}
}
//具体产品Dell
class Dell extends Computer {
@Override
public void print() {
System.out.println("Dell");
}
}
//抽象产品手机
abstract class Phone {
public abstract void print();
}
//具体产品HUAWEI
class Huawei extends Phone {
@Override
public void print() {
System.out.println("Huawei");
}
}
//具体产品小米
class Mi extends Phone {
@Override
public void print() {
System.out.println("Mi");
}
}
抽象工厂模式的优点
- 工厂抽象类创建了多个类型的产品,当有需求时,可以创建相关产品子类和子工厂类来获取。
- 符合开闭原则
抽象工厂模式的缺点
扩展新种类产品时困难。抽象工厂模式需要我们在工厂抽象类中提前确定了可能需要的产品种类,以满足不同品牌的多种产品的需求。但是如果我们需要的产品种类并没有在工厂抽象类中提前确定,那我们就需要去修改工厂抽象类了,而一旦修改了工厂抽象类,那么所有的工厂子类也需要修改,这样显然扩展不方便。
工厂模式源码分析
Calendar的getgetInstance()方法用到了简单工厂模式。如下代码:
public class Source {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
}
}
进入getInstance()查看如下:
/**
* Gets a calendar using the default time zone and locale. The
* <code>Calendar</code> returned is based on the current time
* in the default time zone with the default
* {@link Locale.Category#FORMAT FORMAT} locale.
*
* @return a Calendar.
*/
public static Calendar getInstance()
{
return 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 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;
}