工厂方法 -- Factory Method

2017-03-17 20:00:46   最后更新: 2017-03-17 20:00:46   访问数量:202




在此前的文章中,我们介绍了两个用于创建复杂的产品的设计模式:

抽象工厂模式 -- AbstractFactory

生成器模式 -- Builder

他们有着很多的相似之处,最大的共同点是对调用者隐藏了产品创建的细节,用户只需要使用抽象的工厂或生成器类即可创建出实际的产品

但是有时,抽象类并不能决定实例化那一个类,这样就必须将类的实例化过程延迟到其子类,这就是我们即将要介绍的 Factory Method 模式的适用场景

 

如果我们需要构建一个文档管理器,我们有一个抽象工厂 Application,当用户点击 open 按钮时,调用 Application 的 create 方法,创建 Document,但是 Application 并不知道用户需要创建的是 TextDocument 还是 DrawingDocument,实际的创建动作是在点击时才触发的

Factory Method 就解决了这一尴尬的局面,Application 拥有 TextApplication 和 DrawingApplication 两个子类,他们负责创建实际的 Document,一旦 Application 的子类被创建,那么创建什么类型的具体 Document 也就随之确定下来

 

工厂方法模式主要适用于以下场景:

  1. 一个类不知道他所必须创建的对象的类
  2. 一个类希望由他的子类决定他所创建的对象
  3. 当抽象类拥有多个局部化的“帮助子类”

 

 

 

工厂方法模式由下列组件构成:

  1. Product -- 工厂方法所创建的抽象对象
  2. ConcreteProduct -- 具体的 Product 实现类
  3. Creator -- 抽象的工厂方法,定义了创建抽象的 Product 对象的方法
  4. ConcreteCreator -- 具体的工厂方法,用于创建具体的 ConcreteProduct 对象

 

工厂方法的缺点是需要为每一个 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      工厂      工厂方法     


京ICP备15018585号