Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclassess.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
何时使用
优点
简单工厂模式
介绍工厂方法模式前,先介绍一下简单工厂模式,简单工厂模式也是一种工厂方法模式。
简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。
如果一些对象(产品),已经确定了并不易改变和添加新的产品,那么就可以使用简单工厂模式。下面就是简单工厂的例子:
// 演示简单工厂模式
public class SimpleFactory{
public static void main(String args[]) throws Exception{
Factory factory = new Factory();
factory.produce("PRO5").run();
factory.produce("PRO6").run();
}
}
// 抽象商品
interface MeizuPhone{
void run();
}
// 具体商品X2
class PRO5 implements MeizuPhone{
@Overrid
public void run(){
System.out.println("我是一台PRO5")
}
}
class PRO6 implements MeizuPhone{
@Override
public void run(){
System.out.println("我是一台PRO6")
}
}
// 工厂
class Factory{
MeizuPhone produce(String product) throws Exception{
if(product.equals("PRO5"))
return new PRO5();
else if(produce.equals("PRO6"))
return new PRO6();
throw new Exception("No Such Class");
}
}
很容易看出,简单工厂模式是不易维护的,如果需要添加新的产品,则整个系统都需要修改。如果我们需要添加诸如PRO7、PRO8等产品,直接在工程类中添加即可。但是如果这时候根部不知道还有什么产品,只有到子类实现时才知道,这时候就需要工厂方法模式。
而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以实现起来是比较麻烦的,那么工厂方法模式正式解决这个问题的,下面就介绍工厂方法模式。
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
针对上面的例子,如果使用工厂方法模式,即将工厂定义为一个接口,然后由具体的工厂来确定需要生成什么样的产品,为了与简单工厂比较,这里还是贴上代码:
// 工厂方法模式
public class FactoryMethod{
public static void main(String args[]){
IFactory bigfactory;
bigfactory = new SmallFactory();
bigfactory.produce().run();
bigfactory = new BigFactory();
bigfactory.produce().run();
}
}
// 抽象商品
interface MeizuPhone{
void run();
}
// 具体商品*2
class PRO5 implements MeizuPhone{
@Override
public void run(){
Systemj.out.println("我是一台PRO5");
}
}
class MX5 implements MeizuPhone{
@Override
public void run(){
System.out.println("我是一台MX5");
}
}
// 抽象的工厂
interface IFactory{
MeizuPhone produce();
}
// 工厂*2
class BigFactory implements IFactory{
@Override
public MeizuPhone produce(){
return new PRO5();
}
}
class SmallFactory implements IFactory{
@Override
public MeizuPhone produce(){
return new MX5()
}
}
如果了解Java的集合框架,那么它就是一个很好的例子:
Java中的Collection接口的实现都能通过iterator()方法返回一个迭代器,而不同的实现的迭代器都在该实现中以内部类的方式对Iterator接口实现的,然后通过iterator()方法返回。那么,这个iterator()方法就是一种工厂方法。
可以看到,在这里抽象产品是Iterator接口,具体产品就是Collection接口的实现中对Iterator接口的实现,构造者是Collection接口,其提供的工厂方法就是Iterator iterator();,具体构造者就是Collection的实现。而工厂方法模式的结构,也就是由前面加粗的4部分组成。
如果对Java容器不熟悉,下面再提供一个例子(模仿Iterator,其实顺便也介绍了Iterator):
如果有多种数据结构要遍历,我们就需要一种用于遍历不同结构的工具,首先我们就需要为这个工具定义一个接口(抽象产品),用于描述如何来遍历:
// 只是需要遍历一堆数据,那么只需要2个方法就可以了
public interface Iterator<T> {
boolean hasNext(); // 是否还有下一个元素
T next(); // 得到下一个元素
}
然后就是我们要遍历的目标,而这些目标此处我们暂定为列表,这就是构造者
// 便于介绍,不做多的操作
public interface List<T> {
Iterator<T> iterator(); // 返回一个遍历器
boolean add(T t); // 添加元素到列表
}
对于List可能有多种实现方式,比如数组和链表,此处就简陋的介绍一下,而这些就是具体构造者,而里面有遍历器的具体实现(具体产品),此处以内部类的形式放到了List的实现(具体构造者)里面,也完全可以修改代码将遍历器的实现(具体产品)独立出来:
数组的实现:
package com.anxpp.designpattern.factorymethod;
//方便演示而实现的简陋的数组list
public class ArrayList<T> implements List<T>{
private int size; //存放的元素个数,会默认初始化为0
private Object[] defaultList; //使用数组存放元素
private static final int defaultLength = 10;//默认长度
public ArrayList(){ //默认构造函数
defaultList = new Object[defaultLength];
}
@Override
public Iterator<T> iterator() {
return new MyIterator();
}
//添加元素
@Override
public boolean add(T t) {
if(size<=defaultLength){
defaultList[size++] = t;
return true;
}
return false;
}
//遍历器(具体产品)
private class MyIterator implements Iterator<T>{
private int next;
@Override
public boolean hasNext() {
return next<size;
}
@SuppressWarnings("unchecked")
@Override
public T next() {
return (T) defaultList[next++];
}
}
}
链表实现
//方便演示而实现的简陋的单向链表list
public class LinkList<T> implements List<T>{
private int size; //存放的元素个数,会默认初始化为0
private Node<T> first; //首节点,默认初始化为null
@Override
public Iterator<T> iterator() {
return new MyIterator();
}
@Override
public boolean add(T t) {
if(size==0){
first = new Node<T>(t,null);
size++;
return true;
}
Node<T> node = first;
while(node.next!=null)
node = node.next;
node.next = new Node<T>(t,null);
size++;
return true;
}
//链表节点
private static class Node<T>{
T data;
Node<T> next;
Node(T data,Node<T> next){
this.data = data;
this.next = next;
}
}
//遍历器
private class MyIterator implements Iterator<T>{
private Node<T> next; //下一个节点
MyIterator(){
next = first;
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public T next() {
T data = next.data;
next = next.next;
return data;
}
}
}
使用上述代码(模式的使用)
public class TestUse{
public static void main(String[] args){
// 分别定义两种结构
List<Integer> array = new ArrayList<Integer>();
List<Integer> link = new LinkList<Integer>();
// 添加数据
for(int i = 1 ; i < 8 ; i++){
array.add(i);
link.add(i);
}
// 获得迭代器
Iterator<Integer> ai = array.iterator();
Iterator<Integer> li = link.iterator();
// 遍历并输出
while(ai.hasNext()){
System.out.println(ai.next());
}
System.out.println();
while(li.hasNext()){
System.out.print(li.next());
}
}
}
一抽象产品类派生出多个具体产品类;一抽象工厂类派生出多个具体工厂类;每个具体工厂类只能创建一个具体产品类的实例。 即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。
与简单工厂间的取舍:工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。
如果再分得详细一点,一个工厂可能不只是生产手机(如小米除了手机,连电饭锅都有),但有得工厂智能生成低端的产品,而大一点的工厂可能通常是生成更高端的产品。所以一个工厂是不够用了,这时,就应该使用抽象工厂来解决这个问题。