工厂方法模式——软件设计模式
例子:女娲造人
- 涉及到3个对象:女娲、八卦炉、三种不同肤色的人(白人、黑人、黄种人)
- 女娲可以用场景类Client来表示
- 八卦炉类似一个工厂,负责制造生产产品(即人类)
- 三种不同肤色的人,都是同一接口下的不同实现类
类图
- AbstractHumanFactory是一个抽象类,定义了一个八卦炉具有的整体功能
- HumanFactory是实现类,完成具体的任务——创造人类
- Human接口是人类的总称,三个实现类分别为三类人种
- NvWa(女娲)是一个Client场景类,负责模拟这个场景,并执行相关的任务
- 定义每个人种都有两种方法:getColor()、talk()
人类总称
public interface Human {
public void getColor();
public void talk();
}
人类接口的三个实现类
public class BlackHuman implements Human {
public void getColor(){
System.out.println("皮肤的颜色是black");
}
public void talk(){
System.out.println("黑人说话");
}
}
public class WhiteHuman implements Human {
public void getColor(){
System.out.println("皮肤的颜色是white");
}
public void talk(){
System.out.println("白人说话");
}
}
public class YellowHuman implements Human {
public void getColor(){
System.out.println("皮肤的颜色是yellow");
}
public void talk(){
System.out.println("黄种人说话");
}
}
抽象人类创建工厂
/**
* 作为一个生产的管理者,只要知道生产什么就可以了,而不需要食物的具体信息。
* 八卦炉生产人类的方法输入参数类型应该是Human接口的实现类
*/
public abstract class AbstractHumanFactory{
//使用了泛型Generic,通过定义泛型对createHuman的输入参数产生两种限制
//1. 必须是Class类型
//2. 必须是Human的实现类
public abstract <T extends Human> T createHuman(Class<T> c);
}
人类创建工厂
public class HumanFactory extends AbstractHumanFactory {
public <T extends Human> T createHuman(Class<T> c){
Human human = null;
try {
human = (Human)Class.forName(c.getName()).newInstance();
}catch (Exception e) {
System.out.println("人种生成错误");
}
return (T)human;
}
}
场景类Client:NvWa
public class NvWa{
public static void main(String[] args) {
AbstractHumanFactory abstractHumanFactory = new HumanFactory();
System.out.println("生产白人");
Human whiteHuman = abstractHumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
System.out.println("生产黑人");
Human blackHuman = abstractHumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
System.out.println("生产黄种人");
Human yelloHuman = abstractHumanFactory.createHuman(YellowHuman.class);
yelloHuman.getColor();
yelloHuman.talk();
}
}
工厂方法模式的定义
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
- 在工厂方法模型中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义
- Creator为抽象创建类,也就是抽象工厂
- ConcreteCreator具体如何创建产品类
抽象产品类
public abstract class Product{
//产品类的公共方法
public void method1(){
//doSomething
}
//抽象方法
public abstract void method2();
}
具体产品类
public class ConcreteProduct1 extends Product {
public void method2(){
//doSomething
}
}
public class ConcreteProduct2 extends Product {
public void method2(){
//doSomething
}
}
抽象工厂类
/**
* 抽象工厂类负责定义产品对象的产生
*/
public abstract class Creator{
/**
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String、Enum、Class等,也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
具体工厂类
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T>c ){
Product product = null;
try {
product = (Product)Class.forName(c.getNmae()).newInstance();
}catch (Exception e) {
//异常处理
}
return (T)product;
}
}
场景类Client
public class Client{
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/**
* 继续业务逻辑
*/
}
}
工厂方法模式的优缺点
工厂方法模式的优点
- 良好的封装性
- 代码结构清晰
- 扩展性非常优秀
- 屏蔽产品类,产品类的实现如何变化,调用者都不需要关心,只关心产品的接口,只要接口不变,系统中的上层模块就不会发生变化
- 工厂方法模式是典型的解耦框架
- 高层模块值只需要知道产品的抽象类,其他的实现类都不需要关系,符合迪米特法则,不需要的就不去了解
- 符合依赖倒置原则,只依赖产片类的抽象
- 符合里氏替换原则,可以用产品子类替代产品父类
工厂方法模式的使用场景
- 工厂方法模式是new一个对象的替代品,但是需要慎重地考虑是否增加一个工厂类进行管理,增加代码的复杂度
- 需要灵活的,可扩展的框架时,可以考虑采用工厂方法模式
1.工厂方法模式的扩展——缩小为简单工厂模式
- 一个模块仅需要一个工厂类,没必要生产出来,使用静态的方法就可以
- 类图变得简单,模式是工厂方法模式的弱化
变化
- 去掉了AbstractHumanFactory
- 同时把createHuman方法设置为static静态类型,简化了类的创建过程
源码变化仅HumanFactory和NvWa
人类创建工厂: HumanFactory
public class HumanFactory {
public static <T extends Human> T createHuman(Class<T> c){
Human human = null;
try {
human = (Human)Class.forName(c.getName()).newInstance();
}catch (Exception e) {
System.out.println("人种生成错误");
}
return (T)human;
}
}
场景类Client:NvWa
- 直接HumanFactory的静态方法
public class NvWa{
public static void main(String[] args) {
// AbstractHumanFactory abstractHumanFactory = new HumanFactory();
System.out.println("生产白人");
Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
System.out.println("生产黑人");
Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
System.out.println("生产黄种人");
Human yelloHuman = HumanFactory.createHuman(YellowHuman.class);
yelloHuman.getColor();
yelloHuman.talk();
}
}
2.升级为多工厂模式
多工厂模式的抽象工厂类
- 抽象方法不在需要传递相关参数了,每个具体的工厂都已经非常明确自己的职责:创建自己负责的产片类对象
public abstract class AbstractHumanFactory{
public abstract Human createHuman();
}
各色人种的创建工厂
public abstract class BlackHumanFactory extends AbstractHumanFactory{
public Human createHuman(){
return new BlackHuman();
}
}
public abstract class WhiteHumanFactory extends AbstractHumanFactory{
public Human createHuman(){
return new WhiteHuman();
}
}
public abstract class YellowHumanFactory extends AbstractHumanFactory{
public Human createHuman(){
return new YellowHuman();
}
}
场景类Client
public class NvWa{
public static void main(String[] args) {
// AbstractHumanFactory abstractHumanFactory = new HumanFactory();
System.out.println("生产白人");
Human whiteHuman = (new WhiteHumanFactory()).createHuman();
whiteHuman.getColor();
whiteHuman.talk();
System.out.println("生产黑人");
Human blackHuman = (new BlackHumanFactory()).createHuman();
blackHuman.getColor();
blackHuman.talk();
System.out.println("生产黄种人");
Human yelloHuman = (new YellowHumanFactory()).createHuman();
yelloHuman.getColor();
yelloHuman.talk();
}
}
3.替代单例模式
工厂类
public class SingletonFactory{
private static Singleton singleton;
static{
try {
Class cl = Class.forName(Singleton.class.getName());
//获得无参构造
Constructor constructor = cl.getDeclaredConstructor();
//设置无参构造是可访问的
constructor.setAccessible(true);
//产生一个实例对象
singleton = (Singleton)constructor.newInstance();
}catch (Exception e) {
//异常处理
}
}
public static Singleton getSingleton(){
return singleton;
}
}
单例类
public class Singleton{
//不允许通过new产生一个对象
private Singleton(){
}
public void doSomething(){
//doSomething
}
}
4.延迟初始化lazy initialization
ProductFactory负责产品类对象的创建工作,并通过prMap变量产生一个缓存,对需要再次被重用的对象保留
抽象产品类
public abstract class Product{
//产品类的公共方法
public void method1(){
//doSomething
}
//抽象方法
public abstract void method2();
}
具体产品类
public class ConcreteProduct1 extends Product {
public void method2(){
//doSomething
}
}
public class ConcreteProduct2 extends Product {
public void method2(){
//doSomething
}
}
产品工厂
public class ProductFactory {
private static final Map<String, Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product = null;
//如果Map中已有这个对象
if(prMap.containsKey(type)){
product = prMap.get(type);
}else{
if(type.equals("ConcreteProduct1")){
product = new ConcreteProduct1();
}else{
product = new ConcreteProduct2();
}
prMap.put(type, product);
}
return product;
}
}