工厂模式(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(抽象产品) :定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
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
* Calendar
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;
}