模式的秘密——工厂模式

模式的秘密——工厂模式

一、   工厂模式的概念

工厂模式:为创建对象提供过度接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

二、   工厂模式的应用场景

工厂方法

1、当一个类不知道它所必须创建的对象的类的时候;

2、当一个类希望由它的子类来指定它所创建的对象的时候;

3、当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮组子类是代理者这一信息局部化的时候。

抽象工厂

1、一个系统应当不依赖于产品类实例被创立、组成和表示的细节,这对于所有形态的工厂模式都是重要的

2、这个系统的产品有至少一个的产品族

3、同属于一个产品族的产品是设计成在一起使用的,这一约束必须得在系统的设计中体现出来

4、不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节

三、   工厂模式的实例

在一些制作类APP、游戏、即时通信应用的人物装扮功能中,我们可以选择人物的发型、脸型、眼睛、鼻子、嘴巴、睫毛、眉毛的样子来构造人物形象,类似这样的功能可以通过工厂模式的思想来实现。比如说,现在我们要实现人物发型的功能,我们就可以通过工厂模式来实现,我们就简单的以左偏分、右偏分和中分为例来看一看源码应该如何实现。

1、         首先,我们需要定义一个统一的接口HairInterface,实现画发型的功能

public interfaceHairInterface {

          public void drawHair();

}

2、         然后左偏分、右偏分和中分的子类都实现HairInterface接口

/*

 * 左偏分

 */

public class LeftDirHair implements HairInterface {

 

     @Override

     public void drawHair() {

          // TODO Auto-generated method stub

          System.out.println("左偏分");

     }

 

}

/*

 * 右偏分

 */

public class RightDirHair implements HairInterface {

 

     @Override

     public void drawHair() {

          // TODO Auto-generated method stub

          System.out.println("右偏分");

     }

 

}

3、         需要什么样的发型我们可以通过实例化具体的子类来实现,这样做后期有了新的发型不便于扩展,所以我们可以通过定义工厂来统一定义发型的实例。

 

/*

 * 发型工长

 * 生成发型

 */

public class HairFactory {

     public HairInterface getHair(String key) {

          if ("left".equals(key)) {

               return new LeftDirHair();

          }else if ("right".equals(key)) {

               return new RightDirHair();

          }

          return null;

     }

}

4、         测试

HairFactory factory = new HairFactory();

     HairInterfacehairInterface = factory.getHair("left");

hairInterface.drawHair();

5、         上面我们通过关键字来判读发型,我们可以通过Java的反射机制来对工厂方法进行修改,在HairFactory中添加方法

public HairInterface getHairByClassName(String className) {

          try {

               HairInterfacehair = (HairInterface) Class.forName(className).newInstance();

               return hair;

          }catch (InstantiationException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (IllegalAccessException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (ClassNotFoundException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

          return null;

     }

在测试类中这样调用

HairFactory factory = new HairFactory();

HairInterface left factory.getHairByClassName("LeftDirHair");

left.drawHair();

注:必须是全类名(包名+类名),小编没有创建应用包,这点不提倡

6、         上面的方法我们通过反射来判读发型,感觉关键字太长,不太方便,所以我们在该进一下,我们可以通过type.properties实现全类名和关键字的映射,创建文件type.properties,内容如下:

left=LeftDirHair

right=RightDirHair

7、         通过PropertiesReader读取type.properties文件

/*

 *properties文件读取

 */

public class PropertiesReader{

     public Map<String, String> getProperties(){

          Propertiesprops = new Properties();

          Map<String,String> map = new HashMap<>();

          try {

               InputStreamin = getClass().getResourceAsStream("type.properties");

               props.load(in);

               Enumerationen = props.propertyNames();

               while(en.hasMoreElements()){

                     Stringkey = (String)en.nextElement();

                     Stringproperty = props.getProperty(key);

                     map.put(key, property);

               }

          }catch (Exception e) {

               // TODO: handle exception

               e.printStackTrace();

          }

          return map;

     }

}

8、         在HairFactory中添加改进的方法getHairByClassKey

public HairInterface getHairByClassKey(String key) {

          try {

               Map<String, String> map = new PropertiesReader().getProperties();

              

               HairInterfacehair = (HairInterface) Class.forName(map.get(key)).newInstance();

               return hair;

          }catch (InstantiationException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (IllegalAccessException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (ClassNotFoundException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

          return null;

  }

                  前面我们以人物的发型为例简单讲解了工厂模式的源码实现。那么,比如新的需求圣诞节马上到了,老板要求实现“圣诞系列男孩的装扮”和“圣诞系列女孩装扮”,这个时候我们又该怎么办呢?这个时候我们就可以考虑抽象工厂模式的思想来实现老板的需求,这样的话不管是圣诞系列还是春节系列都so easy!

1、 首先,我们需要定义男孩和女孩的抽象类

public interface Boy {

     public void drawBoy();

}

public interface Girl {

     public void drawGirl();

}

2、 然后,定义圣诞系装扮男孩和女孩的具体实现类

/*

 * 圣诞系男孩装扮

 */

public class MCBoy implements Boy {

 

     @Override

     public void drawBoy() {

          // TODO Auto-generated method stub

          System.out.println("圣诞系列男孩装扮");

     }

 

}

/*

 * 圣诞系列女孩装扮

 */

public class MCGirl implements Girl {

 

     @Override

     public void drawGirl() {

          // TODO Auto-generated method stub

          System.out.println("圣诞系列女孩装扮");

     }

 

}

3、 接着,我们需要定义一个工厂接口用来获取男孩和女孩的实例

public interfacePersonFactory {

     public Boy getBoy();

 

     public Girl getGirl();

}

4、 最后,定义圣诞系装扮工厂实现PersonFactory接口

public class MCFactory implements PersonFactory {

 

     @Override

     public Boy getBoy() {

          // TODO Auto-generated method stub

          return new MCBoy();

     }

 

     @Override

     public Girl getGirl() {

          // TODO Auto-generated method stub

          return new MCGirl();

     }

 

}

5、 验证

PersonFactory factory2 = new MCFactory();

     Girlgirl factory2.getGirl();

girl.drawGirl();

6、 当然什么中秋系装扮、元旦系装扮都和圣诞系装扮实现方式类似。

四、   工厂模式的设计思想

低耦合,一个对象的依赖对象的变化与本身无关

具体产品与客户端剥离,责任分割

五、   总结

工厂方法模式和抽象工厂模式对比

1、工厂模式是一种极端情况的抽象工厂模式,而抽象工厂模式可以看成是工厂模式的推广

2、工厂模式用来创建一个产品的等级结构,而抽象工厂模式是用来创建多个产品的等级结构

3、工厂模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类

工厂模式的优点:

1、系统可以在不修改具体工厂角色的情况下引进新的产品

2、客户端不必关心对象如何创建,明确了职责

3、更好的理解面向对象的原则,面向接口编程,而不是面向实现编程

猜你喜欢

转载自blog.csdn.net/zhimingshangyan/article/details/52349903