第二篇、创建型设计模式——工厂方法模式

前言:从最开始接触编程,到一点点有了些心得体会,到迫切的希望写出漂亮的代码,总会有意识的去寻找途径。当开始接触设计模式的时候,会发现,种种设计模式之间很难区分,甚至觉得极为类似。有时候也会在几种模式之间徘徊,不知道用哪种更好。其实,就设计模式而言,没有最好的,只有最适合的,每种设计模式都有自己的优缺点。每个人都有自己的理解,很难说哪个是正确,哪个是错误。有时候,不用设计模式比用了设计模式更加高效。所以,学习设计模式,个人认为,最重要的还是一种编程的理念,一种编程的思想,灵活的运用继承,封装,多态的特性,比生搬硬套设计模式更加明智。闲话少说,进入正题。

——————————————————————————————————————————————————————————————————

所谓工厂方法模式,就是将上一篇中的工厂类抽象成创建对象的接口,让其子类去决定实例化哪一个类。工厂方法模式使一个类的实例化过程延迟到了其子类中。

之前没有看过,或者不清楚的,可以看上一篇博文:第一篇、创建型设计模式——简单工厂模式:点击打开链接

我们依然用计算程序举例,在上一篇的简单工厂中,我们先实现加减法,再实现乘除法,通过应用简单工厂模式,可以有效的实现易维护、易扩展、易复用、少修改的原则。但是在前言中,我说过,没有最好的模式,只有最适合的,因此,简单工厂也有其自己的缺点与不足。我们一起来分析一下:

首先,回顾一下关键代码,作为简单工厂模式,最关键的就是其工厂类:

public class OperationFactory {  
        public static Operation creatOperation(String str) {  
            Operation operation = null;  
            switch (str) {  
            case "+":  
                operation = new OperationAdd();  
                break;  
            case "-":  
                operation = new OperationSub();  
                break;  
            }  
            return operation;  
        }  
}  

我们通过调用这个工厂类的creatOperation方法,将运算符作为参数传给这个工厂类,得到需要的运算类,从而得到运算结果。当我们需要增加乘除法的时候,仿照加减法运算类写出乘除法运算类,这条满足了对扩展开放和单一职责原则。然后在工厂类中修改switch,添加乘法和除法的case分支,虽然少量的改动,但是依然有改动,这也就是简单工厂的不足了。因为就开放封闭原则来说,我们应该尽量避免修改的发生,因为修改就意味着可能出现问题,可能造成额外的工作量,为了解决这个问题,工厂方法模式应运而生。

1、首先是抽象出运算父类,并实现父类的具体运算子类,这与之前的简单工厂写法相同

public abstract class Operation {  
    public double a = 0.0;  
    public double b = 0.0;  
  
    public abstract double getResult();  
}  
//加法运算类  
public class OperationAdd extends Operation {  
    @Override  
    public double getResult() {  
        return a + b;  
    }  
} 
//减法运算类  
public class OperationSub extends Operation {  
    @Override  
    public double getResult() {  
        return a - b;  
    }  
}  
2、将工厂类抽象出来,这里开始就是区别所在:

public abstract class IFactory {
	public abstract Operation creatOperation();
}

3、具体的工厂类,如加法工厂类,减法工厂类:

public class AddFactory extends IFactory{

	@Override
	public Operation creatOperation() {
		return new OperationAdd();
	}

}
public class SubFactory extends IFactory{

	@Override
	public Operation creatOperation() {
		return new OperationSub();
	}

}
这里将简单工厂的工厂类进行了职责拆分,将其抽象成了工厂父类,然后通过一个个工厂子类去实例化各自的产品对象,如加法工厂AddFactory只负责实例化加法运算类OperationAdd,不关心其他运算类的实例化,这就进一步的分离了功能职责,使程序的耦合度进一步降低,增加了扩展的灵活度。当我需要增加乘法和除法的时候,只需仿照加减法写出乘除法运算类。再仿照加减法工厂类,写出乘除法工厂类,功能扩展就完成了。无需向简单工厂一样,需要修改原来的工厂类。是不是更加贴近了开发封闭原则与单一职责原则。

那么,有人会问,工厂方法就很完美么?其实不然,相信许多人也已经意识到,你还没有在客户端页面调用呢,在客户端调用的时候,同样需要进行逻辑判断,实例化我所需要的运算工厂类。别急,我们再来一起分析一下:

我们在客户端页面调用:

		String operaStr = "-";
		IFactory operaFactory = null;
		switch (operaStr) {
		case "+":
			operaFactory = new AddFactory();
			break;
		case "-":
			operaFactory = new SubFactory();
			break;
		}

		Operation operation = operaFactory.creatOperation();
		operation.a = 2.0;
		operation.b = 1.0;
		double result = operation.getResult();

		System.out.println(result);
我们再来与简单工厂的客户端页面调用进行比较一下:

Operation operation = OperationFactory.creatOperation("-");  
operation.a = 2.0;  
operation.b = 1.0;  
double result = operation.getResult();  
有人会发现,之前用简单工厂,我只需要将运算符传递给工厂,而无需知道运算类的实例化过程,就可以得到想要的结果,客户端只负责数据的获取与展示。但是用了工厂方法的时候,我就需要在客户端进行逻辑判断,实例化出所需要的运算工厂类,这使得客户端的职责增加了。当增加乘除法的时候,简单工厂需要修改工厂类,而工厂方法需要修改客户端,同样没有避免修改啊?

其实,这也是工厂方法的不足,它只是将简单工厂的逻辑判断移到了客户端,并没有解决功能增加时,判断分支的修改。依然存在修改,就没有很好地满足开放封闭原则。那工厂方法的优点在哪里呢?

我们换个角度来分析一下:

假设存在这样一个应用场景,在一个客户端应用中,存在2个不同的业务界面A和B,在A中,我需要用加法的逻辑进行操作,在B中我需要减法的逻辑进行操作。当某一天,这两种功能不能满足我的需求了,我需要增加C和D,分别要求用乘法和除法进行操作,这时候:

1、用简单工厂:我需要增加乘法和除法运算类,然后修改工厂类,最后在C和D中调用。

2、用工厂方法:我需要增加乘法和除法运算类,然后增加乘法和除法运算工厂类,最后在C和D中调用

怎么样,看出区别了么。

所以说,还是前言当中说的,没有最好的,只有最适合的,没有一种设计模式是适合所有场景的,这也是我们学习设计模式中要注意区分与理解的,错误的应用设计模式,反而会增加程序维护扩展的难度。

那有人会,难道没办法避免逻辑分支么?有句比较流行的话:反射反射,程序员的快乐!在以后的博文中,我们会用反射的技术来优化逻辑分支的判断。


小结:简单工厂 VS. 工厂方法

无论是哪种工厂模式,都是用于封装产品对象的创建过程,是客户端仅通过工厂就可以拿到自己需要的产品对象,而无需知道这些对象是怎么组成的。

各自的特点:

简单工厂:在同一个等级结构中,生产任意的产品对象(对于新增加产品对象,比较乏力。因为在工厂类中包含了switch...case的逻辑判断,通过与反射技术的何用,可以起到很好地优化作用)


工厂方法:在同一个等级结构中,生产固定的产品对象(在同一等级结构下,支持新增加产品对象。对增加新的等级结构比较乏力)





  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值