雷锋依然在人间——工厂方法模式
薛磊风常年照顾军队退役的孤寡老人,但他现在住医院了,没有办法照顾老人了。
所以他委托我们去照顾老人,但不会留自己的姓名,像雷锋一样做好事。
简单工厂模式实现
以之前的计算器为例:
- 简单运算工厂类
package SimpleFactory04;
public class OperationFactory {
public static Operation createOperate(String strOperate){
Operation operation = null;
switch (strOperate){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*":
operation = new OperationMul();
break;
case "/":
operation = new OperationDiv();
break;
}
return operation;
}
}
- 客户端代码
package SimpleFactory04;
public class Client {
public static void main(String[] args) {
Operation operation = OperationFactory.createOperate("/");
operation.setNumA(9);
operation.setNumB(2);
double result = operation.getResult();
System.out.println(result);
}
}
工厂方法模式实现
- 工厂接口
package factory01;
public interface Factory {
public abstract Operation createOperation();
}
- 各个运算类对应的工厂
package factory01;
public class AddFactory implements Factory{
@Override
public Operation createOperation() {
return new Add();
}
}
public class SubFactory implements Factory{
@Override
public Operation createOperation() {
return new Sub();
}
}
public class MulFactory implements Factory{
@Override
public Operation createOperation() {
return new Mul();
}
}
public class DivFactory implements Factory{
@Override
public Operation createOperation() {
return new Div();
}
}
- 客户端
package factory01;
public class Client {
public static void main(String[] args) {
// 获取乘法工厂
Factory operationFactory = new MulFactory();
// 由乘法工厂获取乘法类
Operation operation = operationFactory.createOperation();
// 设置A,B
operation.setA(7.0);
operation.setB(10.0);
// 得到结果
double res = operation.getResult();
System.out.println(res);
}
}
简单工厂vs工厂方法
- 简单工厂最大的优点就是工厂类内部包含了必要的逻辑判断,根据客户端的选择动态的实例化相关的类。对于客户端来说,去除了与具体产品的依赖。
如果我想要增加一个a^b的运算,不可避免地要修改我的简单工厂类
,这显然违背了OCP(开发-封闭原则)。
工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。(工厂方法使得一个类的实例化延迟到其子类。)
- 当我们要添加a^b的运算时,只需要添加对应的运算类和工厂类即可,符合OCP,不需要像简单工厂一样还要修改简单工厂类的代码。
- 这样整个工厂和产品体系都没有修改的变化,有的只是扩展的变化。
- 工厂方法把简单工厂内部的判断逻辑移到了客户端。你想要添加功能,本来是修改简单工厂类,现在是修改客户端。
简单工厂实现
- 雷锋“抽象”类
package factor02;
public abstract class LeiFeng {
public void wash(){
System.out.println("洗衣服");
}
public void sweep(){
System.out.println("扫地");
}
public void buyRice(){
System.out.println("买米");
}
}
- “具体的雷锋类”
package factor02;
// 学习雷锋的大学生
public class Underdraduate extends LeiFeng{
}
package factor02;
// 社区志愿者
public class Volunteer extends LeiFeng{
}
- 简单工厂
package factor02;
public class LFFactory {
public static LeiFeng createLeiFeng(String type){
LeiFeng leiFeng = null;
switch (type){
case "学习雷锋的大学生":
leiFeng = new Underdraduate();
break;
case "社区志愿者":
leiFeng = new Volunteer();
break;
}
return leiFeng;
}
}
- 客户端
package factor02;
public class Client {
public static void main(String[] args) {
LeiFeng volunteerA = LFFactory.createLeiFeng("社区志愿者");
volunteerA.buyRice();
LeiFeng volunteerB = LFFactory.createLeiFeng("社区志愿者");
volunteerB.wash();
LeiFeng volunteerC = LFFactory.createLeiFeng("社区志愿者");
volunteerC.sweep();
}
}
工厂方法实现
- 雷锋“抽象”类
package factor02;
public abstract class LeiFeng {
public void wash(){
System.out.println("洗衣服");
}
public void sweep(){
System.out.println("扫地");
}
public void buyRice(){
System.out.println("买米");
}
}
- “具体的雷锋类”
package factor02;
// 学习雷锋的大学生
public class Underdraduate extends LeiFeng{
}
package factor02;
// 社区志愿者
public class Volunteer extends LeiFeng{
}
- “雷锋工厂接口”
package factory03;
public interface Factory {
public abstract LeiFeng createLeiFeng();
}
- “具体的雷锋工厂”
package factory03;
public class VolunteerFactory implements Factory{
@Override
public LeiFeng createLeiFeng() {
return new Volunteer();
}
}
package factory03;
public class UnderdraduateFactory implements Factory{
@Override
public LeiFeng createLeiFeng() {
return new Underdraduate();
}
}
- 客户端
package factory03;
public class Client {
public static void main(String[] args) {
Factory factory = new UnderdraduateFactory();
LeiFeng leiFeng = factory.createLeiFeng();
leiFeng.buyRice();
leiFeng.wash();
leiFeng.sweep();
}
}
工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
都集中封装了对象的创建,使得更换对象时,不需要做大的改动就可以实现。
这还不是最优解,利用“反射”可以解决分支判断问题。