◉◡◉ 您好,欢迎到访伊成个人站!

java设计模式之工厂方法模式

工厂方法模式介绍

定义了一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类。

介绍工厂方法模式之前,整个工厂方法模式分为: 简单工厂模式,工厂方法模式,抽象工厂模式三种。

简单工厂模式 的创建意图就是,把对类的创建初始化全都交给一个工厂来执行,而用户不需要去关心创建的过程是什么样的,只用告诉工厂我想要什么就行了。

而这种方法的缺点也很明显,违背了设计模式的开闭原则,因为如果你要增加工厂可以初始化的类的时候,你必须对工厂进行改建。

工厂方法模式UML类图

“伊成博客”

模式结构

ConcreteCreator: 抽象工厂角色,担任这个角色是工厂方法模式的核心,它是与应用程序无关的。任何在模式中创建对象的工厂类必须实现这个接口。

Creator: 具体工厂角色,担任这个角色的是实现了抽象工厂接口的具体Java类,具体工厂角色含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。

ConcreteProduct: 抽象产品角色,工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。

Product: 具体产品角色,这个角色实现了抽象产品角色所申明的接口。工厂方法模式所创建的每一个对象都是某个具体产品角色的实例。

举个栗子

一个厨师(工厂类)负责所有的烤披萨任务,太累了。于是招了两个厨师分别负责烤披萨和切披萨,之前的厨师升级为厨师长(抽象工厂类),负责教那两位厨师(具体工厂类)烤披萨,自己则不用亲自动手烤披萨了。

下面是抽象产品的角色Pizza的源代码:

1
2
3
4
5
public abstract class Pizza{
public abstract void prepare();
public abstract void bake();
public abstract void cut();
}

具体角色CheesePizza的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CheesePizza extends Pizza{
public void prepare(){
System.out.pringln("准备CheesePizza");
}
public void bake(){
System.out.pringln("准备CheesePizza");
}
public void cut(){
System.out.pringln("准备CheesePizza");
}
public void box(){
System.out.pringln("准备CheesePizza");
}
}

具体角色GreekPizza的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class GreekPizza extends Pizza{
public void prepare(){
System.out.pringln("准备GreekPizza");
}
public void bake(){
System.out.pringln("准备GreekPizza");
}
public void cut(){
System.out.pringln("准备GreekPizza");
}
public void box(){
System.out.pringln("准备GreekPizza");
}
}

抽象工厂角色PizzaFactory的代码,这个角色是使用一个Java接口实现,它声明了一个工厂方法,要求所有的具体工厂角色实现这个工厂方法:

1
2
3
4
public interface PizzaFactory{
//工厂方法
public Pizza createPizza();
}

下面是具体工厂角色CheesePizzaFactory的代码,这个角色实现了抽象工厂角色PizzaFactory所声明的工厂方法:

1
2
3
4
5
6
public class CheesePizzaFactory implements PizzaFactory{
@Override
public Pizza createPizza(){
return new CheesePizza();
}
}

具体工厂角色GreekPizzaFactory的代码,这个角色实现了抽象工厂角色PizzaFactory所声明的工厂方法:

1
2
3
4
5
6
public class GreekPizzaFactory implements PizzaFactory{
@Override
public Pizza createPizza(){
return new GreekPizza();
}
}

客户端角色的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class OrderPizaa{
public static void main(String[] args){
//创建CheesePizzaFactory--具体工厂类
//可以通过反射和配置文件来获取和存储具体工厂类的类名,更换新的具体工厂时无须修改源代码,系统扩展更为方便
PizzaFactory factory = new CheesePizzaFactory();
Pizza pizza = factory.createPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
//创建GreekPizzaFactory()--具体工厂类
pizza = factory.createPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}

输出结果如下:

1
2
3
4
5
6
7
8
准备CheesePizza
正在烤CheesePizza
正在切CheesePizza
正在打包CheesePizza
准备GreekPizza
正在烤GreekPizza
正在切GreekPizza
正在打包GreekPizza

工厂方法模式的优缺点

优点:
1.遵循开闭原则,新增产品类时只需要增加相应的工厂以及产品即可,不需要修改原有的代码。
2.符合单一职责原则,每个工厂类只负责一种产品的创建
3.使用非静态方法来创建产品,利于后续对产品的拓展,可拓展性增加

缺点:
1.一个工厂只能创建一种产品
2.每次增加新的产品时都需要增加对应的工厂类,当产品越来越多的时候系统创建的工厂类就越多,越来越复杂,不利于后期维护。同时,类的创建和销毁可能会对系统造成一定的开销。

工厂方法模式使用案例

1.JDK中体现:Collection.iterator方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Iterator<E> iterator() {
return new Itr();
}

/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;

public boolean hasNext() {
return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}

Collection接口里面定义了许多方法就像size(),isEmpty(),iterator()等等这些方法可以认为是工厂里面的产品,Collection可以看作是一个总的抽象工厂。

它的一些实现这个接口的类,像ArrayList,LinkedHashSet等等可以看作一个个不同的品牌的工厂,而总的产品Iterator接口里面会定义产品所需功能的细节,然后在交给各个品牌不同的工厂来实现。


The end.

支付宝打赏 微信打赏