有款游戏叫模拟人生,我这里就例子就叫北漂人生吧。

北漂人生 规定安家模式

a.结婚 b.买房 c. 买车 d. 生娃

 

先看几种情况:

1. 我初来帝都,按照北漂人生规则,如果要安家,要遵守

a. 结婚

b. 买车(不可以,纳税不够5年)

c. 买房(不可以,纳税不够5年)

d. 生娃(不享受北京相关政策福利)

2. 我来帝都5年,要安家,也遵守

a. 结婚

b. 买房(有资格,看你储备和运气)

c. 买车(同上)

d. 生娃(不享受)

3. 帝都郊区人民

a. 结婚

b. 买房

c. 买车

d. 生娃(可以2个) 

注:以上规则不适用“我爸是李刚”等开挂模式。

 

作为一个全方位的考虑,你要实现很多种情况,但是规则比较固定,所以假如我有个工厂类,并且用if/else来解决 

  1. if(//初来帝都,不够5年){  
  2.   //执行了安家模式abcd,只有结婚无限制,其他有特殊规则  
  3. }else   
  4. if(//来帝都5年){  
  5.   //安家模式abcd,放开部分限制  
  6. }else  
  7. if(//帝都郊区){  
  8.   //安家模式abcd,遵守规则  
  9. }else  
  10. if(//帝都土著){  
  11.   //安家模式abcd,福利分房,补贴  
  12. }  

太乱!时也许你会整理整理,于是对外地人本地人做了个区分 

  1. if(//外地人){  
  2. //5年限制  
  3. }else  
  4. if(//本地人){  
  5. }  

然后你开始面对一个问题,每个if/else里都有abcd,但是又略有不同,如何重构?

一般我们考虑继承或者组合两种方式,设计模式可以考虑策略,装饰器等。那这里就是讲工厂方法,所以就采用继承 

  1. if(//外地人){  
  2.   if(//level A){  
  3.      //类unlocalA的对象  
  4.    }  
  5.   else if(//level B){  
  6.   //类unlocalB的对象  
  7.    }  
  8.   }  
  9. else if(//本地人){  
  10.   if(//level A){  
  11.     //类localA的对象  
  12.   }else if(//level B){  
  13.    //类localB的对象  
  14.   }  
  15.  }  

再次重构呢?能不能更好一点,假如我新增加一个老外模式进来,能不能不修改原来的工厂类了呢?

尝试将工厂分为本地工厂外地工厂,这样再加入新的老外工厂就不会影响其他已经封装的源代码了。

记得在区别 工厂方法 和 抽象工厂的这个图,是这样的: 

假如我添加老外安家: 

 通过上面的推导过程,我们无赖似的推出了个工厂方法模式。再补充一下,这个例子并不是很适合工厂方法,我们来看看工厂方法适合的场景。

 

工厂方法模式适合的情况

我们注意到几个问题

1. 变化少:产品(我们这里的是产品是安家)接口内容不会有太多变化。

2. 松耦合:新增加一工厂以及相关产品,不需要改动原来的代码

3. 相同接口:产品都是实现同一个接口

4. 相同层级:每个工厂,层级都基本相同。 

如果我们仔细回忆一下,spring在对ORM框架和EJB对于安全策略的集成,都与工厂方法有非常相似的地方。 都是制定了一些共同的约束,非常符合我们变化少的原则。

 何时用?

工厂方法模式一般在一些比较大的系统中会用到,尤其在做spring这种组件分离,但遵循某些共同约束的场景下,结合一些其他模式,将会更加灵活强大。

 

我为这个模式写个些粗糙的代码:

层级:

  1. /**   
  2. * 家庭级别   
  3. * @author 书生   
  4. *   
  5. */   
  6. public enum Level {   
  7.     /*高级*/A,   
  8.     /*普通*/B   
  9. }  
  10.  

抽象工厂

  1. /**   
  2. * 创建家庭   
  3. * @author 书生   
  4. *   
  5. */   
  6. public abstract class FamilyBuild {   
  7.     public Family buildFamily(Level level) {   
  8.         Family family;   
  9.         family = marry(level);   
  10.         family.buyHouse();   
  11.         family.buyCar();   
  12.         family.babyBirth();   
  13.         return family;   
  14.     }   
  15.     /**   
  16.      * 结婚组成家庭,传入级别   
  17.      * @param level   
  18.      * @return   
  19.      */   
  20.     protected abstract Family marry(Level level);   
  21. }  
  22.  

一个具体的工厂

  1. public class UnLocalFamilyBuild extends FamilyBuild {   
  2.  
  3.     @Override   
  4.     protected Family marry(Level level) {   
  5.         Family family;   
  6.         if(level==Level.A) {   
  7.             family = new UnLocalSeniorFamily();   
  8.         }else {   
  9.             family = new UnLocalCommonFamily();   
  10.         }   
  11.         return family;   
  12.     }   
  13.  
  14. }  
  15.  

家庭接口

  1. /**   
  2. * 家庭   
  3. * @author 书生   
  4. *   
  5. */   
  6. public abstract class Family {   
  7.     /*户主等相关信息描述*/   
  8.     public String hostName;   
  9.      /*家庭住址*/   
  10.     public String adr;   
  11.     public void buyHouse() {   
  12.          System.out.println("buy house");   
  13.      }   
  14.     public  void marry() {   
  15.          System.out.println("Important moment,Happy Times");   
  16.      }   
  17.     public void babyBirth() {   
  18.          System.out.println("make new people :)");   
  19.      }   
  20.     public void buyCar() {   
  21.          System.out.println("buy a car");   
  22.      }   
  23. }  
  24.  

普通外地人接口 

  1. /**   
  2. * 普通外地人组件家庭   
  3. * @author 书生   
  4. *   
  5. */   
  6. public class UnlocalCommonFamily extends Family {   
  7.     public UnlocalCommonFamily() {   
  8.         hostName = "工作不满5年的外地人";   
  9.         adr = "租房";   
  10.     }   
  11.  
  12.     @Override   
  13.     public void babyBirth() {   
  14.       //TODO 生孩子相关政策   
  15.     }   
  16.  
  17.     @Override   
  18.     public void buyHouse() {   
  19.         // TODO 不足5年,不能买房   
  20.         //完全重写   
  21.     }   
  22.  
  23.     @Override   
  24.     public void buyCar() {   
  25.         // TODO 不足5年,不能买车   
  26.         // 完全重写   
  27.     }   
  28.  
  29. }  
  30.  
  31.   

如果我想创建一个普通外地人家庭,需要

  1. public class TestFactoryMethod {   
  2.     public static void main(String[] args) {   
  3.         FamilyBuild fb = new UnLocalFamilyBuild();   
  4.         Family family = fb.buildFamily(Level.B);   
  5.     }   

 我想你也注意到了,new UnLocalFamilyBuild(); 每一个工厂都有一套自己的规则。如果能做到只要一个配置就得到需要的工厂功能,而不需要知道具体工厂类会不会更好?答案是也许会。我们在spring中也看到有多个Factory的情况,当一个工厂类,包含的信息非常丰富,或者通过类名,能够基本知道他所代表的喊一声时,这已经是一个不错的工厂了。这个可能会引发一个争论,到底精简到什么地步是最好,或者说,设计模式的原则都是合理的吗? 不过这不是我们要讨论的,我们通过此文最重要的是对工厂方法的思想理解。 

 

我上传一下我写的工厂方法的一些代码,大多是伪码。