标签:
有时候,由于产品的多样化,但是产品的功能却有某种共同的联系。我们希望定义一个用于创建产品对象的公共接口,让子类决定去如何实现这个功能。然后,我们定义一个生产产品的“工厂”,所有的产品将从这个工厂里面生产出来,这样我们就使得产品的构造的细节与工厂分离了,这样产品的实现细节就被封装起来了,并且产品的可扩展性也很强。那么,这种设计模式我们称为工厂方法模式。具体的实例有很多,比如说去年的某一阵子脸萌软件爆红,其中就运用到了工厂方法模式来给用户生产各种脸型。
根据我个人的总结,我认为工厂方法模式总共分为四种,它们的具体差别如下表所示:
静态模式 | 工厂中使用静态方法来直接创建各个产品 |
普通模式 | 工厂中使用if-else语句来判断用户需求,进而生产产品 |
映射模式 | 工厂中使用key-value读取配置文件来映射产品种类,进而生产产品 |
反射模式 | 工厂中使用反射生产产品的实例 |
现在我们使用微信的发送文字、发送图片、发送视频三个功能来简单的说明一下工厂方法模式,当然本例中并不去具体实现如何发送文字、图片、视频等内容,只是以此为模板来示范一下。
首先,我们考虑到三个功能都有一个共同点,即都具有发送这一行为,因此,在Java中接口与抽象类的最重要的区别就是接口是对行为的抽象,而抽象类是对类的抽象,具有同一行为的场景下我们优先想到定义一个接口来约束它们,相当于是给它们指定了一个原则,必须要实现接口中定义的这个行为(功能)。
因此,先设计一个公共接口Sendable,其中要定义一个方法send(),是子类必须要实现的功能。
package com.factory.factoryMethod; public interface Sendable { public void send(); }
发送文字:
package com.factory.factoryMethod; public class TextSender implements Sendable { @Override public void send() { System.out.println("发送文字"); } }
package com.factory.factoryMethod; public class PhotoSender implements Sendable { @Override public void send() { System.out.println("发送图片"); } }
package com.factory.factoryMethod; public class VideoSender implements Sendable{ @Override public void send() { System.out.println("发送视频"); } }
下面分别介绍四中不同的工厂设计方法。
普通模式即在工厂中使用传统的if-else来判断用户的需求。如下面的代码所示:
package com.factory.factoryMethod; public class SenderFactory { public Sendable produce(String type) { if ("text".equals(type)) { return new TextSender(); } else if ("photo".equals(type)) { return new PhotoSender(); } else if ("video".equals(type)) { return new VideoSender(); } else { System.err.println("暂无此产品"); return null; } } }
映射模式中采用了配置文件来处理键值对,好处就是用户不需要记得太多的产品类名,只需要记住关键词即可,工厂会自动映射过去。代码实现如下:
package com.factory.factoryMethod; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class SenderFactory { public Sendable produce(String key) { try { PropertiesReader propertiesReader = new PropertiesReader(); Map<String, String> properties = propertiesReader.getProperties(); String className = properties.get(key); Sendable sender = (Sendable) Class.forName(className).newInstance(); return sender; } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return null; } } class PropertiesReader { public Map<String,String> getProperties() { Properties properties = new Properties(); Map<String, String> hashMap = new HashMap<String,String>(); try { InputStream resourceAsStream = this.getClass().getResourceAsStream("type.properties"); properties.load(resourceAsStream); Enumeration<?> propertyNames = properties.propertyNames(); while(propertyNames.hasMoreElements()) { String key = (String)propertyNames.nextElement(); String property = properties.getProperty(key); hashMap.put(key, property); } } catch(Exception ex) { ex.printStackTrace(); } return hashMap; } }
上面代码用到的配置文件为type.properties,内容如下:
T=com.factory.factoryMethod.TextSender P=com.factory.factoryMethod.PhotoSender V=com.factory.factoryMethod.VideoSender
反射模式其实跟上面一种方法差不多,只不过少了配置文件而已,而且没有了关键词,需要提供方法名了,代码如下:
package com.factory.factoryMethod; public class SenderFactory { public Sendable produce(String className) { try { Sendable sender = (Sendable) Class.forName(className).newInstance(); return sender; } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return null; } }
静态模式,顾名思义,在工厂中静态创建产品,不需要创建工厂对象了,这种模式用得比较广泛一点,代码示例如下:
package com.factory.factoryMethod; public class SenderFactory { public static Sendable produceTextSender() { return new TextSender(); } public static Sendable producePhotoSender() { return new PhotoSender(); } public static Sendable produceVideoSender() { return new VideoSender(); } }
当有大量产品需要被创建时,并且具有共同的某些行为时,可以考虑使用工厂模式,将产品实现细节分离开来。而这四种方法中,最常用的是静态创建方法,其他的三种可能由于参数传递错误,导致无法创建,需要熟悉具体的调用参数才行。
标签:
原文地址:http://my.oschina.net/zzw922cn/blog/489614