软件设计模式之工厂模式(JAVA) Java读写配置文件—
什么是工厂模式? 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 简单点来说,工厂模式就是提供一个产生实例化对象的制造厂,每一个工厂都会提供类似的对象(实现共同接口),当我们需要某个类的实例化对象时,我们不需要关心服务端是通过什么方式来获取对象的,我们直接向对应的工厂提出我们的需求即可(实现了客户端和服务端的分离)。 ? 工厂模式分成三类: 1、简单工厂模式(Simple Factory) 2、工厂方法模式(Factory Method) 3、抽象工厂模式(Abstract Factory) 一般我们把简单工厂模式也归为工厂方法模式,然后抽象工厂模式是工厂方法模式的扩展。 ? 1、工厂方法模式 先来看看工厂方法模式的组成: 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。? ? ? 写个小例子,模拟上帝造人事件,上帝根据不同地理位置气候的不同,造了三种不同肤色的人类:黄种人,白种人,黑种人。 ? 这是一个肤色的接口(这里我们粗略先认为他们只有肤色之差) 1 package com.lcw.factory.test1; 2 3 /** 4 * 皮肤接口 5 */ 6 public interface SkinInterface { 7 8 void skin(); 9 10 } 三种肤色的人类,分别是三个实现类(实现SkinInterface接口),由于代码结构一致,这里只给出一个 class YellowRace implements 4 5 @Override 6 skin() { 7 System.out.println("我是黄种人"); 8 } 10 } 然后,如果按照我们以往的惯例,要拿到对应实现类的对象,我们需要SkinInterface si=new YellowRace();这样子,表面上看虽然没有问题,但一类实现类爆发呢?比如有上百千个实现类,那么除了要添加对应的实现类不说,还需要在客户端去"显示调用"暴露出实现类的类名,后期维护起来也很麻烦。 这时我们的工厂类就派上用场了 * 工厂类(返回对象实例) * 6 7 class SkinFactory { 8 9 // key为关键字,决定实例化哪个类对象 10 public SkinInterface getSkin(String key) { 11 if ("black".equals(key)) { 12 return new BlackRace(); 13 } else if ("white"14 WhiteRace(); 15 } if ("yellow"16 YellowRace(); 17 } 18 null; 19 20 } 写个实现类试试吧 import java.util.Map; FactoryTest { 6 7 * @param args 9 static main(String[] args) { 普通调用方法(显示调用) 12 System.out.println("-------------------------普通调用方法-----------------------------"13 SkinInterface yellowRace=14 SkinInterface whiteRace=15 SkinInterface blackRace=16 yellowRace.skin(); 18 whiteRace.skin(); blackRace.skin(); 20 21 22 工厂方法模式调用 23 System.out.println("-------------------------工厂方法模式调用(脱离客户端和服务端)-----------------------------"24 SkinFactory skinFactory= SkinFactory(); 25 SkinInterface skinInterface1=skinFactory.getSkin("black"26 SkinInterface skinInterface2=skinFactory.getSkin("white"27 SkinInterface skinInterface3=skinFactory.getSkin("yellow"28 29 skinInterface1.skin(); 30 skinInterface2.skin(); 31 skinInterface3.skin(); 32 33 } 从上图来看,我们已经达到了基本目的,但之前的问题已经存在,虽然我们解决了客户端的"显示调用",但服务端却多了一堆的if..elseif的判断,如果实现类很多,那么就需要些更多的if..elseif的判断,这效率很明显就低了,因为每次客户端一请求,那么服务端就要做多余的没玩没了的判断。 有没有什么更好的方法的?那必须是有的,Java有个很强大的机制——反射,我们可以利用反射机制,把所有的类名写入到一个配置文件,以后单纯的维护配置文件即可,看下具体实现过程吧。 首先,我们需要一个配置文件skin.properties 1 black=com.lcw.factory.test1.BlackRace 2 yellow=com.lcw.factory.test1.YellowRace 3 white=com.lcw.factory.test1.WhiteRace 然后写一个读取properties文件的类,把关键字(key)=》值(value)封装到一个map集合。这样我们在客户端只需要输入关键字就可以让服务端自动映射到对应的类。 关于Java读取配置文件,不熟悉的小伙伴们可以轻戳《Java读写配置文件——Properties类的简要使用笔记》,帮你们总结好了。 java.io.IOException; java.io.InputStream; java.util.Enumeration; java.util.HashMap; java.util.Properties; 10 11 * 读取配置文件类(读取配置文件信息并把键值对封装成一个Map集合) 12 13 14 PropertiesReader { 15 16 public Map<String,String> getSkinMap(){ 17 18 Map<String,String> map=new HashMap<String,1)">(); 19 20 Properties properties= Properties(); 21 InputStream inStream=getClass().getResourceAsStream("skin.properties"try { 23 properties.load(inStream); 24 Enumeration enumeration=properties.propertyNames();取得配置文件里的所有key值 25 while(enumeration.hasMoreElements()){ 26 String key=(String) enumeration.nextElement(); 27 map.put(key,properties.getProperty(key)); 28 } 29 return map; 30 31 } catch (IOException e) { e.printStackTrace(); 33 34 35 36 37 38 } 当然,此时的工厂类也需要修改了,看看完整代码 20 21 优化版(避免使用if..elseif繁杂判断) 22 SkinInterface getSkinByClassName(String className) { 23 24 (SkinInterface) Class.forName(className).newInstance(); 26 27 } (InstantiationException e) { 29 } (IllegalAccessException e) { (ClassNotFoundException e) { 34 35 36 37 } 完整测试类: 32 33 工厂方法模式调用(优化版) 35 System.out.println("-------------------------工厂方法模式调用(优化版)-----------------------------"36 SkinFactory factory=37 38 SkinInterface skinInterface=factory.getSkinByClassName("com.lcw.factory.test.YellowRace");过于繁杂的包名而且显示调用了,我们可以用配置文件来映射简化 39 skinInterface.skin(); 40 41 PropertiesReader propertiesReader= PropertiesReader(); 42 Map<String,String> map=propertiesReader.getSkinMap();获取配置文件里的map集合 43 SkinInterface sf1=factory.getSkinByClassName(map.get("black")); 44 SkinInterface sf2=factory.getSkinByClassName(map.get("white"45 SkinInterface sf3=factory.getSkinByClassName(map.get("yellow"46 47 sf1.skin(); 48 sf2.skin(); 49 sf3.skin(); 50 51 52 53 54 55 } 看下效果图: 这样一来,虽然我们多做了很多代码工厂,但对于日后维护起来就很方便了,不管添加多少的新的实现类,我们都不需要去改动客户端代码和工厂类代码,只需要在配置文件里添加上对应的关键字(key),和value(完整类名)即可。 ? ? ? 2、抽象工厂模式 ?在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。? 还是一样举个例子,人有男女之别,那么我们以国家来划分,在中国,有中国男孩,女孩,在美国,有美国男孩,女孩。本质上人只有男、女,那么只是一个基础的接口,那么不同的国家,就可以看做是不同的工厂,他们分别可以生产出"属于他们国家的男孩、女孩(产品)"。 来看下具体代码吧 ? 这是产品的基础接口: 1 com.lcw.factory.test2; 2 3 4 *男孩接口(产品接口) 5 6 Boy { 7 boy(); 8 } 2 * 女孩接口(产品接口) * Girl { girl(); 8 } 产品的具体实现:(由于代码结构一致,这里只给出美国) 2 *美国男孩(产品) class AmericaBoy 7 boy() { 10 System.out.println("我是男孩,我来自美国。"12 13 } * 美国女孩(产品) class AmericaGirl girl() { 10 System.out.println("我是女孩,我来自美国。"13 } 抽象工厂接口: *抽象工厂 PersonFactory { Boy getBoy(); Girl getGirl(); 11 12 } 具体工厂实现:(同样的,中国也有相同的具体工厂去实现这个抽象接口,并提供对应的中国男孩、女孩实例,由于代码结构一直,这里就不贴了) *具体工厂类(产生具体实例) class AmericaPersonFactory PersonFactory{ Boy getBoy() { 10 AmericaBoy(); 13 14 Girl getGirl() { 15 AmericaGirl(); 16 17 18 } 来个测试类: PersonFactoryTest { 4 5 6 PersonFactory factory1=new ChinesePersonFactory();取得工厂对象 7 获取所需实例 8 Boy boy1=factory1.getBoy(); 9 Girl girl1=factory1.getGirl(); 10 boy1.boy(); girl1.girl(); 13 14 15 17 PersonFactory factory2= AmericaPersonFactory(); 18 Boy boy2=factory2.getBoy(); 19 Girl girl2=factory2.getGirl(); 22 boy2.boy(); girl2.girl(); 24 25 } 看下实现效果: ? 总结: (1)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。 (或者由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。) ? 作者:Balla_兔子 (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |