工厂模式– 简单工厂,工厂方法,抽象工厂
场景
小张所在公司的游戏,最近很火,但是对于新手玩家太容易被老手打死,所以产品准备新增一个练习模式,给新手来练习,在练习模式下需要产生很多机器人给新手练习,机器人有很多不同的等级不同的等级对玩家的伤害的不同。这次的需求当仁不让的给了小张,毕竟之前的几次小张做的很不错。
小张的需求分析
练习模式下有很多小兵,当用户进入练习模式,需要产生许多不同等级的小兵。并且根据用户的等级产生想匹配等级的小兵。
小张的初步实现
/**
* @Author xuelongjiang
*/
public class User {
private String level = "lower"; //用户默认为新手
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
}
/**
* 小兵接口
* 机器人
* @Author xuelongjiang
*/
public interface Robot {
public void descrition();
public void attack();
}
/**
* @Author xuelongjiang
*/
public class LowerRobot implements Robot {
private Logger logger = LoggerFactory.getLogger(LowerRobot.class);
public void descrition() {
logger.info("我是低等级的机器人");
}
public void attack() {
logger.info("我是低等级机器人伤害为1");
}
}
/**
* @Author xuelongjiang
*/
public class mediumRobot implements Robot {
private Logger logger = LoggerFactory.getLogger(mediumRobot.class);
public void descrition() {
logger.info("我是中等级的机器人");
}
public void attack() {
logger.info("我是中级机器人伤害为2");
}
}
/**
* @Author xuelongjiang
*/
public class HighRobot implements Robot {
private Logger logger = LoggerFactory.getLogger(HighRobot.class);
public void descrition() {
logger.info("我是高等级的机器人");
}
public void attack() {
logger.info("我是高等级机器人伤害为3");
}
}
/**
* @Author xuelongjiang
*/
public class ExerciseModel {
public static void main(String[] args) {
User user = new User();
Robot robot = new ExerciseModel().createRobot(user.getLevel());
robot.attack();
}
//选择创建哪种机器人
public Robot createRobot(String level){
Robot robot = null;
if(level.equals("lower")){
robot = new LowerRobot();
}else if(level.equals("medium")){
robot = new mediumRobot();
}else if(level.equals("high")){
robot = new HighRobot();
}
robot.descrition();
return robot;
}
}
小张简单实现完成后,觉得自己的代码有点问题,不够灵活如果在新加其他等级的小兵,那么他需要在ExerciseModel添加else if这样的设计需要修改,小张去查找他最近看的《设计模式》发现其中又一个不算是模式的模式 简单工厂模式。
简单工厂模式
简单工厂模式,不属于设计模式,因为它没有对修改关闭,但是因为在系统中的创建都由简单工厂产生,所以修改起来只要修改工厂就可以了。所以在《head first 设计模式》中给简单工厂授予了模式荣誉奖,因为它只是一种编码技巧,我们来看看一下简单工厂模式的真身。
和上面的代码差不多,只是我们修改了ExerciseModel并且新建了一个简单工厂类
/**
* 简单工厂类
* @Author xuelongjiang
*/
public class SimlpeFactory {
//选择创建哪种机器人
public Robot createRobot(String level){
Robot robot = null;
if(level.equals("lower")){
robot = new LowerRobot();
}else if(level.equals("medium")){
robot = new mediumRobot();
}else if(level.equals("high")){
robot = new HighRobot();
}
robot.descrition();
return robot;
}
}
/**
* @Author xuelongjiang
*/
public class ExerciseModel {
public static void main(String[] args) {
User user = new User();
SimlpeFactory simlpeFactory = new SimlpeFactory();
Robot robot = simlpeFactory.createRobot(user.getLevel());
robot.attack();
}
}
我们只是把创建小兵的代码放在了简单工厂类,这样在整个系统中创建小兵都是由简单工厂创建,如果有新的小兵,只需要在简单工厂中增加就可以了。
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。
新的场景
产品为了使游戏更加逼真生动,游戏的小兵在等级之上被分为,男性小兵,女性小兵…….出现了一系列的小兵,并且根据用户的姓别产生异性。简单工厂已经不能满足需求,因为简单工厂的if else已经太多了。
所以我们需要使用设计。
小张:王哥,简单工厂不能适合新的的需求,这个需求重构我需要怎样设计。
老王:给你个思路,最近你不是在看设计模式吗,一看就没有好好看,知道工厂方法吗?
小张: 有点印象 ^_^ 。。。
老王: 那你可得好好看书了,你可以把低中高三个等级的小兵创建为工厂,然后在这三个工厂中创建不同性别的小兵。
小张: ^_^ 有点模糊,我去看看设计模式是怎么讲工厂方法的吧。
工厂方法实现
在这个场景中 小兵是产品,由工厂产生,练习模式是使用者。
/**
* @Author xuelongjiang
*/
public class LowerManRobot implements Robot {
private Logger logger = LoggerFactory.getLogger(LowerManRobot.class);
public void descrition() {
logger.info("我是低级的男性机器人");
}
public void attack() {
logger.info("我是低级男性机器人伤害为1");
}
}
/**
* @Author xuelongjiang
*/
public class LowerWomanRobot implements Robot {
private Logger logger = LoggerFactory.getLogger(LowerManRobot.class);
public void descrition() {
logger.info("我是低级的女性机器人");
}
public void attack() {
logger.info("我是低级女性机器人伤害为1");
}
}
/**
* @Author xuelongjiang
*/
public class MediumManRobot implements Robot{
private Logger logger = LoggerFactory.getLogger(MediumManRobot.class);
public void descrition() {
logger.info("我是中级的男性机器人");
}
public void attack() {
logger.info("我是中级男性机器人伤害为2");
}
}
/**
* @Author xuelongjiang
*/
public class MediumWomanRobot implements Robot{
private Logger logger = LoggerFactory.getLogger(MediumWomanRobot.class);
public void descrition() {
logger.info("我是中级的女性机器人");
}
public void attack() {
logger.info("我是中级女性机器人伤害为2");
}
}
/**
* 工厂方法 抽象的
* @Author xuelongjiang
*/
abstract class AbstractMethodFactory {
abstract Robot createRobot(String sex);
}
/**
* 工厂方法- 具体的
* @Author xuelongjiang
*/
public class LowerRobotFactory extends AbstractMethodFactory {
@Override
Robot createRobot(String sex) {
Robot robot = null;
if(sex.equals("man")){
robot = new LowerManRobot();
}else if(sex.equals("woman")){
robot = new LowerWomanRobot();
}
return robot;
}
}
/**
* 工厂方法-- 具体的
* @Author xuelongjiang
*/
public class MediumRobotFactory extends AbstractMethodFactory {
@Override
Robot createRobot(String sex) {
Robot robot = null;
if(sex.equals("man")){
robot = new MediumManRobot();
}else if(sex.equals("woman")){
robot = new MediumWomanRobot();
}
return robot;
}
}
以上就是工厂方法的代码。
工厂方法模式:定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。
抽象工厂
抽象工厂和工厂方法很相向不同的是抽象工厂可以产生多个产品,而工厂方法只能产生一个产品类。
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
依赖倒置
从我们的初步设计到简单工厂再到工厂方法,我们的耦合越来越小。
初步设计:
我们的ExerciseModel和Robot的实现深深耦合。
简单工厂:
我们的ExerciseModel只和Robot的抽象(不是指是接口或者抽象)耦合,练习模式把创建对象的权利交给了工厂,这样实现了解耦。
并且具体的机器人也是依赖Robot。
现在高层模块(ExerciseModel)和底层模块(具体的机器人)都依赖于Robot抽象。
工厂方法和抽象工厂
抽象工厂的任务是定义一个负责创建一组产品的接口。
所以其实工厂方法是潜伏在抽象工厂中的。
要点
所有工厂都是用来封装对象的创建
所有工厂模式都是通过减少应用程序和具体类之间的依赖促进松耦合
依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象
工厂是很有威力的技巧,帮助我们针对抽象编程,而不是针对具体类编程