设计模式学习笔记------简单工厂
简单工厂
一、实例1
1 /** 2 * 定义接口 3 * @author abc 4 * 5 */ 6 public interface Api { 7 public void test1(); 8 } 9 10 /** 11 * 接口实现类1 12 * @author abc 13 * 14 */ 15 public class Impl1 implements Api { 16 17 @Override 18 public void test1() { 19 System.out.println("实现test1方法"); 20 } 21 } 22 23 /** 24 * 接口实现类2 25 * @author abc 26 * 27 */ 28 public class Impl2 implements Api { 29 30 @Override 31 public void test1() { 32 System.out.println("实现test1方法"); 33 } 34 } 35 36 /** 37 * 工厂类 38 * @author abc 39 * 40 */ 41 public class Factory { 42 /** 43 * 根据条件创建不同的实现来 44 * @param condition 实现条件 45 * @return 46 */ 47 public static Api createImpl(int condition) { 48 Api api = null; 49 if (condition == 1) { 50 api = new Impl1(); 51 } else if (condition == 2) { 52 api = new Impl2(); 53 } 54 return api; 55 } 56 57 public static void main(String[] args) { 58 Api api = Factory.createImpl(1); 59 api.test1(); 60 api = Factory.createImpl(2); 61 api.test1(); 62 63 } 64 }
用户可以通过工厂来获取接口的实现类,可直接操作接口定义的方法。用户不需要知道具体方法是如何实现的。
实例1可以实现简单工厂模式,但是存在一个缺点,用户需要传入选择参数,这就说明用户必须知道每个参数的含义,也需要理解每个参数对应的功能处理,从一定的程度上想用户暴露了内部实现细节
二、实例2--配置文件实现
/** * 定义接口 * @author abc * */ public interface Api { public void test1(); } /** * 接口实现类1 * @author abc * */ public class Impl1 implements Api { @Override public void test1() { System.out.println("实现test1方法"); } } /** * 接口实现类2 * @author abc * */ public class Impl2 implements Api { @Override public void test1() { System.out.println("实现test1方法"); } } package cn.itcast.demo; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.xml.ws.FaultAction; /** * 工厂类 * @author abc * */ public class Factory { /** * 根据条件创建不同的实现来 * @param condition 实现条件 * @return */ public static Api createImpl() { Properties p = new Properties(); InputStream in = null; Api api = null; try { in = Factory.class.getResourceAsStream("FactoryTest.properties"); p.load(in); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { api = (Api)Class.forName(p.getProperty("FactoryTest")).newInstance(); } 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 api; } public static void main(String[] args) { Api api = Factory.createImpl(); api.test1(); } } FactoryTest.properties #配置文件 FactoryTest=cn.itcast.demo.Impl1
在实例一中,如果需要添加一个实现类,则需要更改工厂类。二在实例二中,可以通过反射和配置文件(这里用的式properties,一般实际都使用xml配置)就可以实现在调节实现类后,无需更改代码就能将实现类添加到应用中。
三、简单工厂优缺点
优点:
1.帮助封装
简单工厂虽然很简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
2.解耦
通过简单工厂,实现了客户端和具体实现类的解耦
如同上面的例子,客户端根本就不知道具体是由谁类实现,也不知道具体是如何实现的,客户端只是通过工厂获取需要它的接口对象。
缺点:
1.可能增加客户端的复杂度
如果通过客户端的参数了现在具体的实现类,那么就必须让客户端你理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以 选用可配置的方式来实现。
2.不方便扩展子工厂
私有化简单工厂的构造方法,使用静态方法来创建几口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为。不过,通常情况下是不需要为简单工厂创建子的。
四、简单工厂的本质
简单工厂的本质是:选择实现
简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要有具体的实现类类实现,而不是在简单工厂里面来实现。简单工厂的目的在于为客户端来选择相应的实现,从而使得客户端和实现之间解耦。这样一来,具体实现发生了变化,就不用变动客户端,这个变化会被简单工厂吸收和屏蔽掉。
五、何时选择简单工厂模式
1. 如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选用简单工厂,让客户端通过工厂来获取相应的接口,而无需关心具体实现。
2.如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,一个简单工厂可以创建很多的、不相关的对象,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。