(原创)我眼中的设计模式系列之简单工厂模式(一)
简单工厂模式
在日常的软件开发中,我们一般都是按照模块来划分工作的。
场景一:
试想我们现在有这么一个模块,为其他的模块提供服务,比如说我们调用了好几个外部接口,统一返回XML字符串,每个接口返回的XML格式都不同,有的嵌套数组,有的纯数组,有的就是普通的节点XML。但是我们项目需要的是json格式的数据,通常的做法是写几个类,直接new出对象调用,或者交给spring管理进行注入。不管如何这几个解析类都不是在同一个环境中,即使交由Spring管理,就站在这个模块的角度中来说,这几个类并并没有形成自己的模块化数据结构,而是分开和Spring的环境分散的耦合在一起了。代码的结构会非常差。
场景二:
我们的业务模块中需要的类有可能是不相关的,毫无联系的,但是我们在一个比较大型的功能中需要同时用到这些类中的行为,这个时候我认为是可以使用工厂模式。即这些类实现同一个接口,使用工厂去维护他们,只针对我们需要的业务模块的维护,工厂类可以交给Spring管理,作为这个工厂和Spirng的接口,相当于跟Spring的环境有关系但是又不耦合。
下面我举个小例子可以说明工厂模式的使用,直接上代码:
先创建具体行为的Animal接口
package com.bane.example1.executor; /** * * @ClassName: Animal * @Description: TODO(定义动物的接口) * @author 于继伟 * @date 2017-10-20 下午10:06:49 * */ public interface Animal { }
创建具体动物行为的接口:
package com.bane.example1.executor; /** * * @ClassName: CatExecutor * @Description: TODO(Cat的行为接口) * @author 于继伟 * @date 2017-10-20 下午10:02:29 * */ public interface CatExecutor extends Animal { /** * 抓老鼠的行为 */ void catchMouse(); }
package com.bane.example1.executor; /** * * @ClassName: DogExecutor * @Description: TODO(Dog的行为接口) * @author 于继伟 * @date 2017-10-20 下午10:00:12 * */ public interface DogExecutor extends Animal { /** * 看家的方法 */ void door(); }
package com.bane.example1.executor; /** * * @ClassName: SnakeExecutor * @Description: TODO(Snake的行为接口) * @author 于继伟 * @date 2017-10-20 下午10:04:46 * */ public interface SnakeExecutor extends Animal { /** * 咬人的行为 */ void bite(); }
再创建具体的实现:
package com.bane.example1.executor.impl; import com.bane.example1.executor.CatExecutor; /** * * @ClassName: CatExecutorImpl * @Description: TODO(猫具体行为的实现) * @author 于继伟 * @date 2017-10-20 下午10:09:11 * */ public class CatExecutorImpl implements CatExecutor { @Override public void catchMouse() { System.out.println("抓老鼠"); } }
package com.bane.example1.executor.impl; import com.bane.example1.executor.DogExecutor; /** * * @ClassName: DogExecutorImpl * @Description: TODO(狗的行为的具体实现) * @author 于继伟 * @date 2017-10-20 下午10:09:08 * */ public class DogExecutorImpl implements DogExecutor{ @Override public void door() { System.out.println("狗看家"); } }
package com.bane.example1.executor.impl; import com.bane.example1.executor.SnakeExecutor; /** * * @ClassName: SnakeExecutorImpl * @Description: TODO(蛇具体行为) * @author 于继伟 * @date 2017-10-20 下午10:11:19 * */ public class SnakeExecutorImpl implements SnakeExecutor { @Override public void bite() { System.out.println("蛇咬人"); } }
工厂环境中的具体行为者有了,现在创建工厂的接口和实现:
package com.bane.example1.factory; import com.bane.example1.executor.Animal; /** * * @ClassName: AnimalFactory * @Description: TODO(简单工厂接口) * @author 于继伟 * @date 2017-10-20 下午9:57:46 * */ public interface AnimalFactory { /** * 根据类名创建Animal对象 * @param className * @return */ Animal createAnimal(String className); }
package com.bane.example1.factory.impl; import com.bane.example1.executor.Animal; import com.bane.example1.factory.AnimalFactory; /** * * @ClassName: AnimalFactoryImpl * @Description: TODO(动物工厂的具体实现) * @author 于继伟 * @date 2017-10-20 下午10:14:03 * */ public class AnimalFactoryImpl implements AnimalFactory { @Override public Animal createAnimal(String className) { Animal animal = null; try { animal = (Animal) Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return animal; } }
到此为止,我们的简单工厂创建结束,将动物放入动物的工厂中,我们需要用的时候只需要从工厂中获取动物的实例和行为,就可以使用了,测试类:
package com.bane.example1; import com.bane.example1.executor.CatExecutor; import com.bane.example1.executor.DogExecutor; import com.bane.example1.executor.SnakeExecutor; import com.bane.example1.factory.AnimalFactory; import com.bane.example1.factory.impl.AnimalFactoryImpl; /** * * @ClassName: Main * @Description: TODO(主方法测试) * @author 于继伟 * @date 2017-10-20 下午10:21:48 * */ public class Main { public static void main(String[] args) { AnimalFactory animalFactory = new AnimalFactoryImpl(); CatExecutor catExecutor = (CatExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.CatExecutorImpl"); catExecutor.catchMouse(); DogExecutor dogExecutor = (DogExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.DogExecutorImpl"); dogExecutor.door(); SnakeExecutor snakeExecutor = (SnakeExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.SnakeExecutorImpl"); snakeExecutor.bite(); } }
控制台输出如下:
抓老鼠
狗看家
蛇咬人
需要说明的是,我们是用类名利用反射创建的实例,这样可以省去if else的判断,代码更加优雅。至于需要用什么样的方式去创建或者什么样的条件,这个可以自己灵活使用。至此,简单工厂到此为止。
静态工厂
静态工厂,其实跟上面的简单工厂没有任何的区别,无疑是工厂类中构造方法是私有的,方法都是静态的。直接上代码:
创建颜色的接口和具体的颜色实现:
package com.bane.example2.executor; /** * * @ClassName: Color * @Description: TODO(定义颜色行为接口) * @author 于继伟 * @date 2017-10-21 下午12:11:28 * */ public interface Color { void show(); }
具体实现:
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Blue * @Description: TODO(Blue具体实现) * @author 于继伟 * @date 2017-10-21 下午12:13:17 * */ public class Blue implements Color{ @Override public void show() { System.out.println("这是蓝色"); } }
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Red * @Description: TODO(Red具体实现) * @author 于继伟 * @date 2017-10-21 下午12:12:43 * */ public class Red implements Color{ @Override public void show() { System.out.println("我是红色"); } }
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Yellow * @Description: TODO(Yellow具体实现) * @author 于继伟 * @date 2017-10-21 下午12:13:51 * */ public class Yellow implements Color{ @Override public void show() { System.out.println("这是黄色"); } }
最后创建我们的静态工厂:
package com.bane.example2.factory; import com.bane.example2.executor.Color; /** * * @ClassName: ColorFactory * @Description: TODO(静态工厂实现) * @author 于继伟 * @date 2017-10-21 下午12:16:49 * */ public class ColorFactory { private ColorFactory(){} /** * 静态工厂获取Color对象的方法 * @param className * @return */ public static Color createColor(String className){ Color color = null; try { color = (Color) Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return color; } }
最后主方法测试静态工厂:
package com.bane.example2; import com.bane.example2.executor.Color; import com.bane.example2.factory.ColorFactory; /** * * @ClassName: Main * @Description: TODO(主方法测试静态工厂) * @author 于继伟 * @date 2017-10-21 下午12:19:14 * */ public class Main { public static void main(String[] args) { Color blue = ColorFactory.createColor ("com.bane.example2.executor.impl.Blue"); blue.show(); Color red = ColorFactory.createColor ("com.bane.example2.executor.impl.Red"); red.show(); Color yellow = ColorFactory.createColor ("com.bane.example2.executor.impl.Yellow"); yellow.show(); } }
控制台输出:
package com.bane.example2; import com.bane.example2.executor.Color; import com.bane.example2.factory.ColorFactory; /** * * @ClassName: Main * @Description: TODO(主方法测试静态工厂) * @author 于继伟 * @date 2017-10-21 下午12:19:14 * */ public class Main { public static void main(String[] args) { Color blue = ColorFactory.createColor ("com.bane.example2.executor.impl.Blue"); blue.show(); Color red = ColorFactory.createColor ("com.bane.example2.executor.impl.Red"); red.show(); Color yellow = ColorFactory.createColor ("com.bane.example2.executor.impl.Yellow"); yellow.show(); } }
控制台输出:
这是蓝色
我是红色
这是黄色
至此,静态工厂结束。
抽象工厂
抽象工厂其实就是集中了好几种的工厂,常用的例子是我们的家有厨房,卫生间,房间。这三个都可以看作工厂。厨房里有菜刀,锅等等,是具体的事物行为;卫生间有马桶,淋浴头等具体的事物行为;房间有衣柜,床等具体的行为。今天我举了一个更容易理解的例子。我们的公司有各个部门,例如行政部管的是后勤服务等等,财务部管的是财务和结算等等,开发部负责软件的开发。公司就是一个抽象工厂,而这三个部门就是抽象工厂的具体工厂,抽象工厂定义行为,具体的工厂实现行为。至于我们刚才说的具体三个部门作为工厂,其实,每个部门内部还有很多员工和级别,这又可以继续往下分和扩展,但是我们一般不会那么做。因为那样类的结构过于复杂,跟我们设计模式的初衷不相符。下面直接上代码:
创建Department接口,没有任何行为,主要是为了统一部门的表现形式
package com.bane.example3.executor; /** * * @ClassName: Company * @Description: TODO(公司的接口) * @author 于继伟 * @date 2017-10-21 下午12:36:38 * */ public interface Department { }
具体部门接口:
package com.bane.example3.executor; /** * * @ClassName: CaiWuBuExecutor * @Description: TODO(财务部的行为接口) * @author 于继伟 * @date 2017-10-21 下午12:29:14 * */ public interface CaiWuBuExecutor extends Department{ /** * 结算的方法 */ void jiesuan(); }
package com.bane.example3.executor; /** * * @ClassName: KaiFabuExecutor * @Description: TODO(开发部的行为接口) * @author 于继伟 * @date 2017-10-21 下午12:28:42 * */ public interface KaiFabuExecutor extends Department { /** * 开发的方法 */ void kaifa(); }
package com.bane.example3.executor; /** * * @ClassName: XingZhengBuExecutor * @Description: TODO(行政部的行为接口) * @author 于继伟 * @date 2017-10-21 下午12:29:33 * */ public interface XingZhengBuExecutor extends Department { /** * 后勤的方法 */ void houqin(); }
部门的具体实现:
package com.bane.example3.executor.impl; import com.bane.example3.executor.CaiWuBuExecutor; /** * * @ClassName: CaiWuBuExecutorImpl * @Description: TODO(财务部具体实现) * @author 于继伟 * @date 2017-10-21 下午12:47:44 * */ public class CaiWuBuExecutorImpl implements CaiWuBuExecutor { @Override public void jiesuan() { System.out.println("财务部负责结算"); } }
package com.bane.example3.executor.impl; import com.bane.example3.executor.KaiFabuExecutor; /** * * @ClassName: KaiFabuExecutorImpl * @Description: TODO(开发部具体实现) * @author 于继伟 * @date 2017-10-21 下午12:48:17 * */ public class KaiFabuExecutorImpl implements KaiFabuExecutor { @Override public void kaifa() { System.out.println("开发部负责开发"); } }
package com.bane.example3.executor.impl; import com.bane.example3.executor.XingZhengBuExecutor; /** * * @ClassName: XingZhengBuExecutorImpl * @Description: TODO(行政部具体实现) * @author 于继伟 * @date 2017-10-21 下午12:48:48 * */ public class XingZhengBuExecutorImpl implements XingZhengBuExecutor { @Override public void houqin() { System.out.println("行政部负责后勤"); } }
跟之前一样,具体的行为有了,可以定义工厂类了:
package com.bane.example3.factory; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.executor.XingZhengBuExecutor; /** * * @ClassName: AbstractFactory * @Description: TODO(抽象工厂) * @author 于继伟 * @date 2017-10-21 下午12:23:46 * */ public abstract class AbstractCompanyFactory { /** * 构建财务部 * @param className * @return */ public CaiWuBuExecutor createCaiwuBu(String className){return null;} /** * 构建开发部 * @param className * @return */ public KaiFabuExecutor createKaiFabu(String className){return null;} /** * 构建行政部 * @param className * @return */ public XingZhengBuExecutor createXingZhengBu(String className){return null;} }
package com.bane.example3.factory.sub; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.Department; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: CaiWuBuFactory * @Description: TODO(财务部的工厂) * @author 于继伟 * @date 2017-10-21 下午12:26:53 * */ public class CaiWuBuFactory extends AbstractCompanyFactory { @Override public CaiWuBuExecutor createCaiwuBu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (CaiWuBuExecutor) department; } }
package com.bane.example3.factory.sub; import com.bane.example3.executor.Department; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: KaiFaBuFactory * @Description: TODO(开发部的工厂) * @author 于继伟 * @date 2017-10-21 下午12:25:53 * */ public class KaiFaBuFactory extends AbstractCompanyFactory { @Override public KaiFabuExecutor createKaiFabu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (KaiFabuExecutor) department; } }
package com.bane.example3.factory.sub; import com.bane.example3.executor.Department; import com.bane.example3.executor.XingZhengBuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: XingZhengBuFactory * @Description: TODO(行政部的工厂) * @author 于继伟 * @date 2017-10-21 下午12:26:12 * */ public class XingZhengBuFactory extends AbstractCompanyFactory{ @Override public XingZhengBuExecutor createXingZhengBu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (XingZhengBuExecutor) department; } }
最后写主方法测试:
package com.bane.example3; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.executor.XingZhengBuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; import com.bane.example3.factory.sub.CaiWuBuFactory; import com.bane.example3.factory.sub.KaiFaBuFactory; import com.bane.example3.factory.sub.XingZhengBuFactory; /** * * @ClassName: Main * @Description: TODO(抽象工厂测试) * @author 于继伟 * @date 2017-10-21 下午12:22:48 * */ public class Main { public static void main(String[] args) { //1.获取具体的工厂 //财务部的工厂 AbstractCompanyFactory caiwuFactory = new CaiWuBuFactory(); //开发部的工厂 AbstractCompanyFactory kaifaFactory = new KaiFaBuFactory(); //行政部的工厂 AbstractCompanyFactory xingZhengFactory = new XingZhengBuFactory(); //2.从工厂中获取具体的部门职能 //财务职能 CaiWuBuExecutor caiwu = caiwuFactory.createCaiwuBu ("com.bane.example3.executor.impl.CaiWuBuExecutorImpl"); //开发职能 KaiFabuExecutor kaifa = kaifaFactory.createKaiFabu ("com.bane.example3.executor.impl.KaiFabuExecutorImpl"); //后勤职能 XingZhengBuExecutor xingzheng = xingZhengFactory.createXingZhengBu ("com.bane.example3.executor.impl.XingZhengBuExecutorImpl"); caiwu.jiesuan(); kaifa.kaifa(); xingzheng.houqin(); } }
控制台输出:
财务部负责结算
开发部负责开发
行政部负责后勤
上面就是我们工厂模式常用的三种表现形式,从上面的代码我们不难看出接口的作用,面向接口编程是JAVA开发中非常重要的一个理念,或者说是思想,根据SOA的思想来说,暴露出来的一定是接口,接口实现的对象类型的控制和扩展,在面向对象程序的设计中具有非常至关重要的意义。至于面向接口编程,大家可以搜索一下相关的文章去阅读。
其实我们的Spring就是一个非常大的工厂模式,阅读过源码的同学可以知道,Spring基于BeanFactory,创建出Bean,但是又维护着自己的数据结构,源于工厂,但是比工厂的设计复杂太多太多。工厂模式我的理解就是这样。