简单工厂模式&工厂方法模式

一、简单工厂模式

软件设计的目标:可维护、可复用、可扩展、灵活性好!

通过封装、继承、多态把程序的耦合度降低,使程序容易修改,并且易于复用。

以一个简单的计算器程序(加减乘除)为例,实现该程序有多种方式:

  1. 在main方法里把计算器的逻辑写完;
  2. 在包含主方法的类里面定义一个方法,将加减乘除的逻辑放到该方法里。main方法调用此方法;
  3. 重新定义一个计算器类,将加减乘除的方法挪到该类中。main方法调用该类的方法。

1和2中方法的调用者和被调用者高度重合,耦合度非常高。3减低了耦合度,调用者和被调用者分离,但是所有的计算方法拥挤在一个类中,修改程序变得危险。

假如一个新手需要在计算器类中新增一个方法,但是他不小心改动了其他已有的方法,这样就很危险了!

利用继承和多态的特点完善下

定义一个抽象父类 Operation,Operation 类中定义两个成员变量 numberA 和 numberB,以及一个抽象方法 getResult()。

加减乘除分别定义一个单独的类 OperationAdd、OperationSub、OperationMul、OperationDiv 都继承 Operation 类

加减乘除类都需要重写抽象父类的 getResult(),我们将计算逻辑放到 getResult() 里。

public abstract class Operation {
  public double numberA=0;
  public double numberB=0;

  public abstract double getResult();
}

public class OperationAdd extends Operation {
  public double getResult() {
    double result=0;
    result = numberA+numberB;
    return result;
  }
}

public class OperationSub extends Operation {
  public double getResult() {
    double result=0;
    result = numberA-numberB;
    return result;
  }
}

public class OperationMul extends Operation {
  public double getResult() {
    double result=0;
    result = numberA*numberB;
    return result;
  }
}

public class OperationDiv extends Operation {
  public double getResult() {
    double result=0;
    result = numberA/numberB;
    return result;
  }
}

测试方法

public class Test {
  public static void main(String[] args) {
    double numberA=1;
    double numberB=2;
       //定义引用变量operation用以指向不同的实例(多态)。
    Operation opAdd = new OperationAdd();
    opAdd.numberA=numberA;
    opAdd.numberB=numberB;
    double resultAdd = opAdd.getResult();
    System.out.println("resultAdd=="+resultAdd);

    Operation opSub = new OperationSub();
    opSub.numberA=numberA;
    opSub.numberB=numberB;
    double resultSub = opSub.getResult();
    System.out.println("resultSub=="+resultSub);

    Operation opMul = new OperationMul();
    opMul.numberA=numberA;
    opMul.numberB=numberB;
    double resultMul = opMul.getResult();
    System.out.println("resultMul=="+resultMul);

    Operation opDiv = new OperationDiv();
    opDiv.numberA=numberA;
    opDiv.numberB=numberB;
    double resultDiv = opDiv.getResult();
    System.out.println("resultDiv=="+resultDiv);
  }
}

现在程序之间的耦合度大大降低,如果需要添加其他的运算方法,只需创建一个类,继承 Operation 类,实现 getResult() 即可。

二、工厂方法模式

工厂模式介绍:http://www.runoob.com/design-pattern/factory-pattern.html

为什么要用工厂模式?

个人理解:将创建对象这件事进一步封装。调用者原先需要知晓“加减乘除”具体的实现类,现在将创建实现类的任务交给工厂(工厂类负责创建)。调用者不需要知道具体实现类是什么,只需要根据一些特殊标记“+”、“-”、“*”、“/”来获取对象的实例即可

运用工厂模式完善如下:

public class TestFactory {
    public static Operation creatOperation(String operate) {
        Operation op = null;
        switch (operate) {
        case "+":
            op = new OperationAdd();
            break;
        case "-":
            op = new OperationSub();
            break;
        case "*":
            op = new OperationMul();
            break;
        case "/":
            op = new OperationDiv();
            break;
        default:
            break;
        }
        return op;
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Operation op = null;
        op = TestFactory.creatOperation("+");
        op.numberA=1;
        op.numberB=2;
        double result = op.getResult();
        System.out.println("result=="+result);
    }
}

上面根据工厂模式的改造已经达到要求了,这里只有一个工厂类,负责创建“加减乘除”类。现在试想一下,如果工厂类不止一个,对“加减乘除”类都增加一个对应的工厂类,会是什么情况?

先构建一个工厂接口

public interface IFactory {
    Operation createOperation();
}

然后为“加减乘除”各建一个具体工厂去实现 IFactory 接口

public class AddFactory implements IFactory {
    @Override
    public Operation createOperation() {
        return new OperationAdd();
    }
}

public class SubFactory implements IFactory {
    @Override
    public Operation createOperation() {
        return new OperationSub();
    }
}

public class MulFactory implements IFactory {
    @Override
    public Operation createOperation() {
        return new OperationMul();
    }
}

public class DivFactory implements IFactory {
    @Override
    public Operation createOperation() {
        // TODO Auto-generated method stub
        return new OperationDiv();
    }
}

测试方法

public class Test {    
    public static void main(String[] args) {
        IFactory openFactory = new AddFactory();
        Operation op = openFactory.createOperation();
        op.numberA=1;
        op.numberB=2;
        double resultAdd = op.getResult();
        System.out.println("resultAdd=="+resultAdd);
    }
}

我们发现,这样的写法不但没有简化代码,而且增加了很多类。原本我们增加一个计算的需求只需要增加一个功能类,再修改工厂类就可以了,现在不但增加功能类,还需要增加对应的工厂类,而且原本调用哪个计算类是由工厂类判断,主程序只需传一个“标记”即可,现在是由主程序自己判断该调用哪个工厂类来获取所需的功能类。

增加了代码却没有减少操作,为什么要这样改变?

我们把第一种模式称为简单工厂模式,第二种模式称为工厂方法模式,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据 main 方法的“标记”动态实例化相关的类,对于 main 方法来说,去除了与具体计算类的依赖。但是这样违反了“开放-封闭原则”,增加计算方法都需要取修改工厂类,不但对扩展开放了,也对修改开放了。于是工厂方法模式来了。

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。

工厂方法模式实现时,main 方法需要去决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,工厂方法把简单工厂的内部逻辑判断移到了 main 方法中进行。想要加功能,本来是改工厂类的,而现在是修改 main 方法。

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个计算方法,就需要加一个计算工厂类,增加了额外的开发量。

至于 main 方法里的判断问题,可以利用“反射”解决。

posted @ 2018-11-16 16:24  认真对待世界的小白  阅读(232)  评论(0编辑  收藏  举报