回顾 简单工厂模式 ,它虽然实现了对象创建和使用的分离,但是每新增个产品就要修改工厂类 还是违背了OCP开闭原则 而工厂方法模式可以解决这个问题
工厂方法模式
工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有以下四个角色
- 抽象产品:定义了产品的规范,描述了产品的主要特征和功能
- 具体产品:实现了抽象产品定义的接口,由具体工厂创建
- 抽象工厂:提供了创建产品的接口
- 具体工厂:主要实现抽象工厂的抽象方法完成具体产品的创建
【案例】
假设有家咖啡店 它目前只卖美式咖啡和拿铁咖啡,但是随着业务的发展,它又加入了卡布奇诺和摩卡咖啡, 小张、小王、小李想喝不同的咖啡,请设计程序完成咖啡店的点餐功能(还是这个案例)
抽象产品
public abstract class Coffee{
abstract String getName();
void addSugar(){ System.out.println("加糖"); }
void addMilk(){ System.out.println("加奶"); }
}
具体产品
美式咖啡
public class AmericanCoffee extends Coffee {
String getName(){
return "美式咖啡";
}
}
拿铁咖啡
public class LatteCoffee extends Coffee {
String getName(){
return "拿铁咖啡";
}
}
抽象工厂
提供了创建产品的接口
public interface CoffeeFactory{
Coffee createCoffee();
}
具体工厂
美式咖啡工厂
public class AmericanCoffeeFactory implements CoffeeFactory{
public Coffee createCoffee(){
return new AmericanCoffee();
}
}
拿铁咖啡工厂
class LatteCoffeeFactory implements CoffeeFactory{
public Coffee createCoffee(){
return new LatteCoffee();
}
}
点餐
public class CoffeeStore {
public Coffee orderCoffee(CoffeeFactory factory){
Coffee coffee = factory.createCoffee();
coffee.addSugar();
coffee.addMilk();
System.out.println(coffee.getName()+"制作中...");
return coffee;
}
public static void main(String[] args) {
CoffeeStore store = new CoffeeStore();
CoffeeFactory factory = new AmericanCoffeeFactory(); //小张想喝美式咖啡
store.orderCoffee(factory);
CoffeeFactory factory1 = new LatteCoffeeFactory(); //小王想喝拿铁咖啡
store.orderCoffee(factory1);
}
}
现在想要加入马布奇诺或摩卡咖啡就无需修改工厂类,只需要在创建一个具体的产品类和一个具体的产品工厂就可以实现,满足了OCP开闭原则
//新添加的具体产品类
public class Cappuccino extends Coffee{
String getName(){return "卡布奇诺";}
}
//新添加的具体工厂类
public class CappuccinoFactory implements CoffeeFactory{
public Coffee createCoffee(){
return new Cappuccino();
}
}
这时小李想喝卡布奇诺就可以在主方法中new CappuccinoFactory
public static void main(String[] args) {
CoffeeStore store = new CoffeeStore();
CoffeeFactory factory1 = new LatteCoffeeFactory(); //小王想喝拿铁咖啡
store.orderCoffee(factory1);
CoffeeFactory factory2 = new CappuccinoFactory(); //小李想喝卡布奇诺
store.orderCoffee(factory2);
}
工厂方法模式的优缺点
- 优点:
1、用户只需要知道具体工厂的名称就可以得到你想要的产品,无需知道产品的创建过程
2、在系统增加新的产品只需要添加具体产品类和对应的具体工厂类,无需对原工厂进行任何修改,满足OCP开闭原则 - 缺点
1、每增加一个产品就要增加一个具体的产品类和对应的具体工厂类,这增加了系统的复杂度
2、抽象产品只能生产一种产品
工厂方法模式在JDK中的应用
抽象产品类
public interface Iterator<E> {
boolean hasNext();
E next();
}
具体产品类
//ListItr 迭代器(LinkList内部类)
private class ListItr implements ListIterator<E> {
ListItr(int index) {
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {//重写的代码...}
public E next() {//重写的代码...}
}
//Itr 迭代器(ArrayList内部类)
private class Itr implements Iterator<E> {
Itr() {}
public boolean hasNext() {//重写的代码...}
public E next() {//重写的代码...}
}
抽象工厂
public interface Collection<E> extends Iterable<E> {
//其他代码...
Iterator<E> iterator();
//其他代码...
}
具体工厂
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
//其他代码...
public Iterator<E> iterator() {
return new Itr();
}
//其他代码...
}
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
//其他代码...
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
//其他代码...
}
使用具体产品
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//List<String> list = new LinkedList<>();
//下面的代码不用改想使用不同的迭代器就new不同的工厂对象即可
Iterator<String> iterator = list.iterator();
}
}
另外还有DataFormat类中getInstance()方法使用的是工厂方法模式
Calendar类中的getInstance()方法也是使用的工厂方法模式