工厂设计模式--Factory
模拟场景:女娲造人,第一次经验不足造出白人,第二次时间太紧,造出黑人,第三次才造出黄种人。
Human接口:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * human接口,因为不同色种的human会有相同的动作,只是实现不同 5 */ 6 public interface Human { 7 void getColor(); //得到肤色 8 void doSomething(); //一些其他动作 9 }
创建不同肤色的human
WhiteHuman类:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * 白人,肯定是human,所以从human接口继承 5 */ 6 public class WhiteHuman implements Human { 7 public void getColor() { 8 System.out.println("白人的肤色是白色的。。。"); 9 } 10 public void doSomething() { 11 System.out.println("我是白人"); 12 } 13 }
BlackHuman类:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * 黑人,肯定是human,所以从human接口继承 5 */ 6 public class BlackHuman implements Human { 7 public void getColor() { 8 System.out.println("黑人的肤色是黑色的。。。"); 9 } 10 public void doSomething() { 11 System.out.println("我是黑人"); 12 } 13 }
YellowHuman类:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * 黄种人,肯定是human,所以从human接口继承 5 */ 6 public class YellowHuman implements Human { 7 public void getColor() { 8 System.out.println("黄种人的肤色是黄色的。。。"); 9 } 10 public void doSomething() { 11 System.out.println("我是黄种人"); 12 } 13 }
AbstractHumanFactory接口:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * 生产human的工厂,可以进行human的生产 5 */ 6 public interface AbstractHumanFactory { 7 abstract <T extends Human> T createHuman(Class<T> c); //根据class类型创建出指定的human 8 }
HumanFactory类:
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin human工厂的具体实现类,创建具体的human对象 4 */ 5 public class HumanFactory implements AbstractHumanFactory { 6 @SuppressWarnings("unchecked") 7 public <T extends Human> T createHuman(Class<T> c) { 8 Human human = null; // 声明human对象,不管是什么肤色的human,肯定都是human的子类 9 try { 10 //反射创建human对象,注意human中要有一个午餐的构造器 11 human = (Human) Class.forName(c.getName()).newInstance(); 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 return (T)human; //返回human对象,泛型 16 } 17 }
NvWa类
1 package com.zqz.dp.factorymethod; 2 /** 3 * @author Qin 4 * 女娲类,要用humanFactory来生成human 5 */ 6 public class NvWa { 7 public static void main(String[] args) { 8 //创建一个human生成工厂 9 AbstractHumanFactory factory=new HumanFactory(); //父类实例指向子类对象 10 System.out.println("第一次经验不足生成白人=======================:"); 11 Human whiteHuman=factory.createHuman(WhiteHuman.class); //反射生成对象 12 whiteHuman.getColor(); 13 whiteHuman.doSomething(); 14 System.out.println("第二次烤太久生成黑人=======================:"); 15 Human blackHuman=factory.createHuman(BlackHuman.class); //反射生成对象 16 blackHuman.getColor(); 17 blackHuman.doSomething(); 18 System.out.println("第三次终于生成黄种人=======================:"); 19 Human yellowHuman=factory.createHuman(YellowHuman.class); //反射生成对象 20 yellowHuman.getColor(); 21 yellowHuman.doSomething();}
这样就完成了human的创建
工厂方法是指定义一个创建对象的接口,让子类决定实例化哪一个类。也就是说工厂方法将子类的实例化延迟到了子类。
工厂方法的优点:
1、 良好的封装性,代码结构清晰;有约束,规定xxxHuman要继承Human类。
2、 可拓展性高;如上面的例子如果要再创建一个其他肤色的Otherhuman,只需要让Otherhuamn类继承Huamn类即可,工厂类不需要进行修改。
3、 屏蔽产品类;也就是说在生成Human的时候,不需要知道Human的任何属性或者方法,只知道我要创建一个Human即可。即我可以不管Human类怎么实现,我只关心如果创建一个Human。
4、 解耦性强。
工厂方法的使用场景
1、 工厂方法模式是new一个对象实例化的一个替代品,所以在所有需要生成对象的地方都可以使用。但是在使用的时候要考虑清楚是否真的需要,会否添加代码的复杂度。
2、 需要灵活的,可拓展的框架时可以考虑
3、 异构项目中
4、 测试驱动开发的框架下
工厂方法的拓展
1、 缩小为简单工厂
在上面的场景中,只需要一个工厂的存在即可,那么就可以把创建human实例的createHuman()方法定义成static的,那么就可以不需要abstractHumanFactory的存在了。
修改的代码如下:
HumanFactory:
1 package com.zqz.dp.staticfactory; 2 /** 3 * @author Qin human工厂的具体实现类,创建具体的human对象 4 */ 5 public class HumanFactory{ 6 @SuppressWarnings("unchecked") 7 public static <T extends Human> T createHuman(Class<T> c) { 8 Human human = null; // 声明human对象,不管是什么肤色的human,肯定都是human的子类 9 try { 10 //反射创建human对象,注意human中要有一个午餐的构造器 11 human = (Human) Class.forName(c.getName()).newInstance(); 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 return (T)human; //返回human对象,泛型 16 } 17 }
NvWa:
1 package com.zqz.dp.staticfactory; 2 /** 3 * @author Qin 4 * 女娲类,要用humanFactory来生成human 5 */ 6 public class NvWa { 7 public static void main(String[] args) { 8 //创建一个human生成工厂 9 System.out.println("第一次经验不足生成白人=======================:"); 10 Human whiteHuman=HumanFactory.createHuman(WhiteHuman.class); 11 //反射生成对象 12 whiteHuman.getColor(); 13 whiteHuman.doSomething(); 14 System.out.println("第二次烤太久生成黑人=======================:"); 15 Human blackHuman=HumanFactory.createHuman(BlackHuman.class); //反射生成对象 16 blackHuman.getColor(); 17 blackHuman.doSomething(); 18 System.out.println("第三次终于生成黄种人=======================:"); 19 Human yellowHuman=HumanFactory.createHuman(YellowHuman.class); //反射生成对象 20 yellowHuman.getColor(); 21 yellowHuman.doSomething(); } 22 }
2、 升级为多个工厂
在上面的操作中,是否会觉得humanFactory兼顾的任务太多了呢?因为要创建白种人、黑种人和黄种人三种不同肤色的human。可能你会觉得说不会啊,这样刚好啊。但是可能在项目中,如果只用一个humanFactory(这里只是举例而已),那么要创建好几百中不同肤色的human,那这个时候你是否还会觉得说很乱呢?
所以在这里,可以升级为多个工厂,在这个场景中就是要有三个Factory,来生成不同的Human。
修改代码如下:
AbstractHumanFactory:
1 package com.zqz.dp.manyfactory; 2 /** 3 * @author Qin 4 * 生产human的工厂,可以进行human的生产 5 */ 6 public interface AbstractHumanFactory { 7 abstract Human createHuman(); //生成human的工厂,具体生成什么肤色的交给具体的factory 8 }
WhiteFactory:
1 package com.zqz.dp.manyfactory; 2 /** 3 * @author Qin 4 * 创建白种人的factory 5 */ 6 public class WhiteFactory implements AbstractHumanFactory { 7 public Human createHuman() { 8 return new WhiteHuman(); //返回白种人实例 9 } 10 }
BlackFactory:
1 package com.zqz.dp.manyfactory; 2 /** 3 * @author Qin 4 * 创建黑种人的factory 5 */ 6 public class BlackFactory implements AbstractHumanFactory { 7 public Human createHuman() { 8 return new BlackHuman(); //返回黑种人实例 9 } 10 }
YellowFactory:
1 package com.zqz.dp.manyfactory; 2 /** 3 * @author Qin 4 * 创建黄种人的factory 5 */ 6 public class YellowFactory implements AbstractHumanFactory { 7 public Human createHuman() { 8 return new YellowHuman(); //返回黄种人实例 9 } 10 }
NvWa:
1 package com.zqz.dp.manyfactory; 2 /** 3 * @author Qin 4 * 女娲类,要用humanFactory来生成human 5 */ 6 public class NvWa { 7 public static void main(String[] args) { 8 //创建一个human生成工厂 9 System.out.println("第一次经验不足生成白人=======================:"); 10 Human whiteHuman=(new WhiteFactory()).createHuman(); //指定的工厂生成指定的实例 11 whiteHuman.getColor(); 12 whiteHuman.doSomething(); 13 System.out.println("第二次烤太久生成黑人=======================:"); 14 Human blackHuman=(new BlackFactory()).createHuman(); //指定的工厂生成指定的实例 15 blackHuman.getColor(); 16 blackHuman.doSomething(); 17 System.out.println("第三次终于生成黄种人=======================:"); 18 Human yellowHuman=(new YellowFactory()).createHuman(); //指定的工厂生成指定的实例 19 yellowHuman.getColor(); 20 yellowHuman.doSomething(); 21 } 22 }
在这里是反而麻烦了,只是简单举个实例而已
3、 替代单例模式
Singleton类:
1 package com.zqz.dp.singletonfactory; 2 /** 3 * @author Qin 4 * 单例类 5 */ 6 public class Singleton { 7 private Singleton(){}; //构造方法私有化 8 public void doSomething(){}; //自己的操作 9 }
SingletonFactory
1 package com.zqz.dp.singletonfactory; 2 import java.lang.reflect.Constructor; 3 /** 4 * @author Qin 5 * 生成单例的factory 6 */ 7 public class SingletonFactory { 8 private static Singleton singleton=null; 9 static { //静态代码块进行加载 10 try { 11 Class<?> c1=Class.forName(Singleton.class.getName()); //反射取得对象 12 Constructor<?> con=c1.getDeclaredConstructor(); //取得singleton的构造器 13 con.setAccessible(true); //因为singleton构造器被私有化,在这里设置为可访问 14 singleton=(Singleton) con.newInstance(); //反射取得对象 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 public static Singleton getSingleton(){ 20 return singleton; //返回实例 21 } 22 }