两种模式的思路非常像:
相同的部分在于:
都是先从操作中抽象出整体,得到一个*别的普通类/抽象类。
public abstract class FatherClass { public abstract void operate();
}
再让子类继承这个父类去override 相关的方法
public class OperationA extends FatherClass{ @Override public void operate() { //方法具体实现 } }
public class OperationB extends FatherClass{ @Override public void operate() { //方法具体实现 } }
不同之处在于调用子类的思路不同。
简单工厂模式的思路就是:先创建一个工厂类,在工厂类内部通过if或者switch方法来判断调用哪个子类。
最典型的比如设计计算器的时候。
可以首先抽象出一个 【计算/compution】的概念 (顶层抽象类),然后让其他子类继承这个抽象类,并实现抽象方法compute,在里面写操作。
在简单工厂模式下,使用一个静态方法,传入操作符,根据操作符的类型去 new 一个对应的子类。
public class OperationFactory { public static Operation createOperate(String operate){ Operation operation = null; switch (operate){ case "+": operation = new Add(); break; case "-": operation = new Sub(); break; case "*": operation = new Multi(); break; case "/": operation = new Div(); break; } return operation; } }
我们在调用的时候在main函数里可以这样写:
//调用工厂方法生成 操作 实例 Operation operation = OperationFactory.createOperate("+"); //调用实例的成员方法获取最终结果 double result = operation.getResult(arg1, arg2);
可以看到主要是通过一个引用operation,指向被引用的子类对象。很明显这里就是利用java的多态特性——在工厂方法创建出子类对象实例后, 使用到了多态特性去调用子类中的相关方法。
相关的缺点是:
每次新增一类操作的时候都要去Factory类中做出修改。
策略模式的不同主要体现在,创建出来的是一个处理策略的类,在这个策略类里面不进行子类的实例化。
public class StrategyHandler{ Strategy strategy; public StrategyHandler(Strategy strategy){
this.strategy = strategy;
} //传入自己构造的策略子类生成的对象
public void StrategyInterface(){
//调用子类对象的方法
strategy.method();
}
}
这个策略类中通过构造参数把具体的策略对象传进来了,也就意味着
在调用StrategyHandler的时候,调用者自己根据需求策略首先new 一个子类对象出来,再传入其构造方法中。
public static void main(String[] args) { StrategyHandler sh; sh = new StrategyHandler(new StrategyA()); sh.handleInterface(); sh = new StrategyHandler(new StrategyB()); sh.handleInterface(); }
尽管最后利用的还是java的多态特性,但是可以看到,StrategyHandler只是把子类对象strategya,赋值给StrategyHandler中的strategy成员变量。其中StrategyHandler并没有参与子类对象的创建。子类对象的创建还是依赖于 外部调用者。
其缺点在于:虽然不用在新增子类的时候修改StrategyHandler ,但是我们在调用new StrategyHandler()给构造器传参的时候,很多情况下是不清楚到底有多少个策略子类的。
通常说,简单工厂模式属于 创建型模式,因为我们在工厂类中根据传入的参数进行了相关子类对象的创建操作。
而策略模式属于行为型模式,因为最后StrategyHandler中成员变量stragety引用的实际对象完全要依赖于外部的行为。
实际操作中,通常是把两者结合在一起进行。
比如上面的计算器的例子
在简单工厂模式下,调用者调用的时候需要用到FatherClass这个*父类去承载由OperationFactory生成的子类对象实例,需要调用者知道有这两个类的存在。
而策略模式下,则需要调用者知道所有的FatherClass的子类存在。
那么不妨综合一下,直接定义一个OperationContenxt类,在构造器中传入类型参数,在成员方法中进行判断,根据不同参数创建不同的FatherClass的子类对象。
调用者得到的就是一个OperationContenxt类的对象,直接调用operationContext对象的相关方法即可(子类方法调用写在该方法中)。
注意:这种结合仅仅解决了两个问题
1)简单工厂模式下调用者必须知道*父类FatherClass 这个问题。简单工厂模式下使用FatherClass obj = operateFactory.createInstance()
策略模式的引入,使得全程通过operationContext这一个对象,不必关心*父类 FatherClass ,直接创建一个operationContext对象搞定。全程操作这个operationContext对象即可。(实际上就是把原来通过调用工厂类的静态方法获取FatherClass 子类对象,然后通过子类对象.子类方法 的方式 改为 调用工厂类的成员方法获取工厂类的实例,工厂类对象.工厂类方法。)
2)策略模式下,调用者必须知道所有的策略子类的问题。
现在通过一个标识 传入OperationContenxt类的构造方法中,由OperationContenxt类去new 子类对象,调用者不必关心内部到底有多少策略类、策略类的名字是什么等等,因为这些都写在OperationContenxt这个工厂类的方法当中了。
其他的问题像每次新增操作都要新建一个子类,并且需要修改OperationContenxt中的代码这些问题是没有得到解决的。
这两种模式都有着非常明显的共同缺点:
当操作/策略 不停增加的时候,需要不停的加入子类去extends父类。容易造成系统冗余