在此前的文章中,我们介绍了两个用于创建复杂的产品的设计模式:
抽象工厂模式 -- AbstractFactory
生成器模式 -- Builder
他们有着很多的相似之处,最大的共同点是对调用者隐藏了产品创建的细节,用户只需要使用抽象的工厂或生成器类即可创建出实际的产品
但是有时,抽象类并不能决定实例化那一个类,这样就必须将类的实例化过程延迟到其子类,这就是我们即将要介绍的 Factory Method 模式的适用场景
如果我们需要构建一个文档管理器,我们有一个抽象工厂 Application,当用户点击 open 按钮时,调用 Application 的 create 方法,创建 Document,但是 Application 并不知道用户需要创建的是 TextDocument 还是 DrawingDocument,实际的创建动作是在点击时才触发的
Factory Method 就解决了这一尴尬的局面,Application 拥有 TextApplication 和 DrawingApplication 两个子类,他们负责创建实际的 Document,一旦 Application 的子类被创建,那么创建什么类型的具体 Document 也就随之确定下来
工厂方法的缺点是需要为每一个 ConcreteProduct 创建对应的 ConcreteCreator,参数化工厂方法可以解决这个问题
abstract class Creator {
public Product create(ProductTypeEnum productType) {
switch (productType) {
case FIRST_PRODUCT:
return new FirstProduct();
case SECOND_PRODUCT:
return new SecondProduct();
}
}
}
class ConcreteCreator extends Creator {
@Override
public Product create(ProductTypeEnum productType) {
switch (productType) {
case FIRST_PRODUCT:
return new MyFirstProduct();
case THIRD_PRODUCT:
return new ThirdProduct();
default:
return super.create(productType);
}
}
}
在上面的例子中,通过参数 productType 我们的工厂方法可以知道具体生产的 Product 对象是什么,我们的创建仍然是延迟到了子类中,只是抽象的 Creator 父类中拥有了默认的创建方式
我们还是以此前的 MazeGame 作为例子来说明工厂方法模式的运用
Creator
package com.techlog.designpattern.mazegame.service;
import com.techlog.designpattern.mazegame.model.Door;
import com.techlog.designpattern.mazegame.model.Maze;
import com.techlog.designpattern.mazegame.model.Room;
import com.techlog.designpattern.mazegame.model.Wall;
/**
* Created by techlog on 2017/3/17.
*/
public abstract class AbstractMazeGameCreator {
public Maze makeMaze() {
return new Maze();
}
public Room makeRoom(int roomNo) {
return new Room(roomNo);
}
public Wall makeWall() {
return new Wall();
}
public Door makeDoor(Room room1, Room room2) {
return new Door(room1, room2);
}
}
我们在一个抽象的 Creator 中设置了创建各个组件的默认方法,具体的 ConcreteCreator 继承该类,可以去复写其中的创建方法,也可以使用父类默认的方法
MazeGameCreator
接下来我们就来创建我们的 MazeGameCreator
package com.techlog.designpattern.mazegame.service;
import com.techlog.designpattern.mazegame.constant.DirectionEnum;
import com.techlog.designpattern.mazegame.model.*;
import java.util.HashMap;
import java.util.Map;
import static com.techlog.designpattern.mazegame.constant.DirectionEnum.*;
/**
* Created by techlog on 2017/3/17.
*/
public class MazeGameCreator extends AbstractMazeGameCreator {
@Override
public Maze makeMaze() {
Maze maze = new Maze();
Room room1 = makeRoom(1);
Room room2 = makeRoom(2);
Door door = new Door(room1, room2);
Map<DirectionEnum, AbstractModel> room1sides = new HashMap<>();
room1sides.put(NORTH, new Wall());
room1sides.put(EAST, door);
room1sides.put(SOUTH, new Wall());
room1sides.put(WEST, new Wall());
room1.setSides(room1sides);
Map<DirectionEnum, AbstractModel> room2sides = new HashMap<>();
room2sides.put(NORTH, new Wall());
room2sides.put(EAST, new Wall());
room2sides.put(SOUTH, new Wall());
room2sides.put(WEST, door);
room2.setSides(room2sides);
maze.addModel(room1);
maze.addModel(room2);
maze.addModel(door);
return maze;
}
}
这个类使用了父类的默认方法,只复写了 makeMaze 来创建一个我们指定的 MazeGame
BoomMazeGameCreator
设想我们现在需要创建一个墙体会爆炸的 BoomMazeGame,那么我们就通过继承 AbstractMazeGameCreator 来实现一个 BoomMazeGameCreator
package com.techlog.designpattern.mazegame.service;
import com.techlog.designpattern.mazegame.constant.DirectionEnum;
import com.techlog.designpattern.mazegame.model.*;
import java.util.HashMap;
import java.util.Map;
import static com.techlog.designpattern.mazegame.constant.DirectionEnum.*;
/**
* Created by techlog on 2017/3/17.
*/
public class BoomMazeGameCreator extends AbstractMazeGameCreator {
@Override
public Maze makeMaze() {
Maze maze = new Maze();
Room room1 = makeRoom(1);
Room room2 = makeRoom(2);
Door door = new Door(room1, room2);
Map<DirectionEnum, AbstractModel> room1sides = new HashMap<>();
room1sides.put(NORTH, new BoomWall(50));
room1sides.put(EAST, door);
room1sides.put(SOUTH, new BoomWall(50));
room1sides.put(WEST, new BoomWall(50));
room1.setSides(room1sides);
Map<DirectionEnum, AbstractModel> room2sides = new HashMap<>();
room2sides.put(NORTH, new BoomWall(50));
room2sides.put(EAST, new BoomWall(50));
room2sides.put(SOUTH, new BoomWall(50));
room2sides.put(WEST, door);
room2.setSides(room2sides);
maze.addModel(room1);
maze.addModel(room2);
maze.addModel(door);
return maze;
}
@Override
public Wall makeWall() {
return new BoomWall(50);
}
}
因为 BoomWall 有爆炸范围参数,所以我们需要复写 makeWall 方法来创建独特的 BoomWall
技术帖
龙潭书斋
java
设计模式
模式
设计
factory
design pattern
工厂
工厂方法