工厂方法模式介绍
有时候,由于产品的多样化,但是产品的功能却有某种共同的联系。我们希望定义一个用于创建产品对象的公共接口,让子类决定去如何实现这个功能。然后,我们定义一个生产产品的“工厂”,所有的产品将从这个工厂里面生产出来,这样我们就使得产品的构造的细节与工厂分离了,这样产品的实现细节就被封装起来了,并且产品的可扩展性也很强。那么,这种设计模式我们称为工厂方法模式。具体的实例有很多,比如说去年的某一阵子脸萌软件爆红,其中就运用到了工厂方法模式来给用户生产各种脸型。
工厂方法模式分类
根据我个人的总结,我认为工厂方法模式总共分为四种,它们的具体差别如下表所示:
静态模式
工厂中使用静态方法来直接创建各个产品
普通模式
工厂中使用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 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 getProperties() {
Properties properties = new Properties();
Map hashMap = new HashMap();
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();
}
}
工厂方法模式总结
当有大量产品需要被创建时,并且具有共同的某些行为时,可以考虑使用工厂模式,将产品实现细节分离开来。而这四种方法中,最常用的是静态创建方法,其他的三种可能由于参数传递错误,导致无法创建,需要熟悉具体的调用参数才行。