java思想和我们生活息息相关。工厂模式也可以在生活中找到大量的例子。
大多数人都玩过网游,就拿当前比较火的剑灵来说,进入剑灵游戏第一步就是创建角色,有剑士、刺客、力士、灵剑等角色。如果你是游戏开发者,你会如何设计一个框架来给用户选择角色呢?
首先,我们应该有个接口,用来定义角色类型。
接口:
public interface CustomRole{}
其次应该有一个角色库,用来给用户提供角色选择,比如用户输入了角色类型、名称、种族、阵营、性别等等参数后,我们就应该从角色库匹配一个对应的角色提供给用户。
角色库的类:
public class RoleFactory{}
角色库中包含创建角色的方法 :
/** * 创建角色 * @param roleType 角色类型 * @param uName 角色名称 * @param uSex 角色性别 * @param uCamp 角色阵营 * @return */ public CustomRole createRole(String roleType, String uName, String uSex, String uCamp ){ if(roleType.equals("JianShi")){ return new JianShi(uName, uSex, uCamp); }else if(roleType.equals("CiKe")){ return new CiKe(uName, uSex, uCamp); } return null; }
我们继续定义角色,有那么多的角色,角色不同种类有相同的属性,我们先定义一个基类实现CustomRole接口:
/** * 角色的基类用于扩展角色。 * */ public abstract class BaseRole implements CustomRole { protected String roleType; protected String uName; protected String uSex; protected String uCamp; }
通过基类,我们扩展具体的“剑士”这个类:
/** *剑士 * */ public class JianShi extends BaseRole{ public JianShi(String name, String sex , String camp) { this.uName = name; this.uSex = sex; this.uCamp = camp; } }
现在我们就可以用角色工厂创建一个角色了:
private void testFactory() { RoleFactory roleFactory = new RoleFactory(); JianShi mJianShi = (JianShi) roleFactory.createRole("JianShi", "一只小剑客", "男", "天辉军团"); }
以上是第一种方法,继续说第二种方法,等说完在比较。
第二种方法和第一种方法稍有不同,保持角色基类和其子类不变,我们把工厂本身也具体化一下:有剑士工厂,有刺客工厂等等:
首先,我们定义一个工厂接口:
public interface CustomFactory { public CustomRole createCustomRole(String uName, String uSex, String uCamp); }
里面有个接口方法:创建角色,注意和第一种方法中工厂里的创建角色方法是不是有一丢丢不同?那就是不用传角色类型了!
接着,我们创建具体的“剑士”这个角色的工厂:
public class JianShiFactory implements CustomFactory { @Override public CustomRole createCustomRole(String uName, String uSex, String uCamp) { return new JianShi(uName, uSex, uCamp); } }
就是实现了CustomFactory 接口和其中的创建角色方法,返回了一个具体的剑士角色。
测试:
private void testFactort2() { CustomFactory jainshiFactory = new JianShiFactory(); JianShi mJianShi = (JianShi) jainshiFactory.createCustomRole("一只小剑客", "男", "天辉军团"); } private void testFactory() { RoleFactory roleFactory = new RoleFactory(); JianShi mJianShi = (JianShi) roleFactory.createRole("JianShi", "一只小剑客", "男", "天辉军团"); }
并且附上第一种方式的测试,对比。
通过对比我们可以发现,第二种方式比第一种方式多了一个接口,少了一个传入参数。
总结:方案一在实例化时必须要知道你要得到的是什么角色(角色类型),才能创建对应角色;第二种则不需要,通过工厂名称就可以知道要创建的是什么角色了。
个人觉得第一种适合子类种类不多的情况,不然需要写很多if()else去过滤类型。第二种适合子类型较多的情况,但是代码量要多点。