简单工厂模式与工厂方法模式的区别

与世无争的帅哥 提交于 2019-12-15 13:43:18

转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51628921

One----简单工厂模式:

一,基本知识:

(1)定义:简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。

(2)理解:简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

二,实现方法和角色:

(1)实现方式:简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

(2)角色和责任:如图:


工厂(Creator)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。

工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
抽象产品(Product)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

 三,优缺点:

(1)优点:在于工厂类中包含了必要的逻辑,根据客户需要的条件动态实例化相关的类,

对客户端来说,去掉了与具体产品的依赖。

(2)缺点:工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,当增加新的东东时,会违反开放-封闭原则


四,例子:

四则运算:简单工厂模式:



运算类:Operation:

  1. public class Operation {
  2. double numberA = 0;
  3. double numberB = 0;
  4. //两个get方法和set方法
  5. public double getNumberA() {
  6. return numberA;
  7. }
  8. public void setNumberA(double numberA) {
  9. this.numberA = numberA;
  10. }
  11. public double getNumberB() {
  12. return numberB;
  13. }
  14. public void setNumberB(double numberB) {
  15. this.numberB = numberB;
  16. }
  17. //getResult方法
  18. public double getResult() {
  19. double result = 0d;
  20. return result;
  21. }
  22. }
简单工厂模式类:OperationFactory

  1. /**
  2. * 多肽实现
  3. *
  4. * @author maiyu
  5. *
  6. */
  7. public class OperationFactory {
  8. public static Operation createOperate(String operate) {
  9. Operation oper = null;
  10. switch (operate) {
  11. case "+":
  12. // 向上转型
  13. oper = new NumberAdd();
  14. break;
  15. case "-":
  16. oper = new NumberSub();
  17. break;
  18. case "*":
  19. oper = new NumberMul();
  20. break;
  21. case "/":
  22. oper = new NumberDiv();
  23. break;
  24. default:
  25. break;
  26. }
  27. return oper;
  28. }
  29. }

四个运算类:

  1. /**
  2. * 加法类,继承父类Operation
  3. *
  4. * @author maiyu
  5. *
  6. */
  7. public class NumberAdd extends Operation {
  8. @Override
  9. public double getResult() {
  10. // 假如某一天公司老板要求在乘法增加一个开根号,即可只需要改动这里
  11. // double result = Math.sqrt(getNumberA() + getNumberB());
  12. double result = getNumberA() + getNumberB();
  13. return result;
  14. }
  15. }

  1. /**
  2. * 减法类,继承父类Operation
  3. *
  4. * @author maiyu
  5. *
  6. */
  7. public class NumberSub extends Operation {
  8. @Override
  9. public double getResult() {
  10. double result = getNumberA() - getNumberB();
  11. return result;
  12. }
  13. }
  1. /**
  2. * 乘法类,继承父类Operation
  3. *
  4. * @author maiyu
  5. *
  6. */
  7. public class NumberMul extends Operation {
  8. @Override
  9. public double getResult() {
  10. double result = getNumberA() * getNumberB();
  11. return result;
  12. }
  13. }

  1. /**
  2. * 除法类,继承父类Operation
  3. *
  4. * @author maiyu
  5. *
  6. */
  7. public class NumberDiv extends Operation {
  8. @Override
  9. public double getResult() {
  10. double result = 0d;
  11. if (getNumberB() != 0) {
  12. result = getNumberA() / getNumberB();
  13. } else {
  14. try {
  15. throw new Exception("除数不能为0");
  16. } catch (Exception e) {
  17. // TODO Auto-generated catch block
  18. e.printStackTrace();
  19. }
  20. // System.out.println("除数不能为0!");
  21. // System.out.println("以下结果是错误的!");
  22. }
  23. return result;
  24. }
  25. }

客户端:Program

  1. import java.util.Scanner;
  2. /**
  3. * 客户端
  4. * @author maiyu
  5. *
  6. */
  7. public class Program {
  8. public static void main(String[] args) {
  9. try {
  10. // 输入端
  11. Scanner scanner = new Scanner(System.in);
  12. System.out.println("请输入数字A : ");
  13. String numberA = scanner.next();
  14. System.out.println("请输入操作符(+,-,*,/):");
  15. String numberOperation = scanner.next();
  16. System.out.println("请输入数字B : ");
  17. String numberB = scanner.next();
  18. // 在这里调用格式工厂的方法
  19. Operation oper;
  20. oper = OperationFactory.createOperate(numberOperation);
  21. oper.numberA = Double.parseDouble(numberA);
  22. oper.numberB = Double.parseDouble(numberB);
  23. double numberResult = oper.getResult();
  24. // 打印结果
  25. System.out.println("输出结果为:" + numberResult);
  26. } catch (Exception e) {
  27. System.out.println("您的输入有误:");
  28. e.printStackTrace();
  29. }
  30. }
  31. }
输出:

  1. 请输入数字A :
  2. 8
  3. 请输入操作符(+,-,*,/):
  4. /
  5. 请输入数字B :
  6. 3
  7. 输出结果为:2.6666666666666665
  8. 请输入数字A :
  9. 8
  10. 请输入操作符(+,-,*,/):
  11. /
  12. 请输入数字B :
  13. 0
  14. java.lang.Exception: 除数不能为0
  15. 输出结果为:0.0
  16. at operation.NumberDiv.getResult(NumberDiv.java:16)
  17. at operation.Program.main(Program.java:24)

但这时,如果客户需求,需要增加求M的N次方的运算,在简单工厂里,就是先增加”求M得N次方“的类,然后去更改工厂方法,

增加Case语句来判断,但这时岂不是修改了原来的类,违背了开放--封闭原则,,,

那么这时就要考虑工厂方法模式了,


TWO-----工厂方法模式

一,基本知识:

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

如下图:


(2) 英文:Factory Method

二,四个要素:

工厂接口:工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。


工厂实现:在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。


产品接口:产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。


产品实现:实现产品接口的具体类,决定了产品在客户端中的具体行为。


三,优点:创建对象的接口,让子类去决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码。工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

四,理解:如下图,上面那个例子可这样改:



利用依赖倒置原则,把工厂类抽象出一个接口,里面只有一个创建抽象产品的方法,然后所有的要生成具体类的工厂去实现这个接口,这样:

一个简单工程模式的工厂类就变成了一个工厂抽象接口和多个具体生成对象的工厂,当我们需要增加例如M的N次方时,就不需要去修改原有的工厂类,只需要增加此功能的运算类和相应的工程类即可。如上图所示。


下面以一个学雷锋的例子:

雷锋类:

  1. class LeiFeng {
  2. public void Sweep(){
  3. System.out.println("扫地");
  4. }
  5. public void Wash(){
  6. System.out.println("洗衣服");
  7. }
  8. public void BuyRice(){
  9. System.out.println("买米");
  10. }
  11. }

工厂接口:

  1. interface IFactory {
  2. LeiFeng createLeiFeng();
  3. }

大学生工厂:

  1. public class UndergraduateFactory implements IFactory{
  2. @Override
  3. public LeiFeng createLeiFeng() {
  4. return new Undergraduate();
  5. }
  6. }

志愿者工厂:

  1. public class VolunteerFactory implements IFactory{
  2. @Override
  3. public LeiFeng createLeiFeng() {
  4. return new Volunteer();
  5. }
  6. }

大学生类:

  1. public class Undergraduate extends LeiFeng {
  2. public void Sweep(){
  3. System.out.println("大学生扫地");
  4. }
  5. public void Wash(){
  6. System.out.println("大学生洗衣服");
  7. }
  8. public void BuyRice(){
  9. System.out.println("大学生买米");
  10. }
  11. }

志愿者类:

  1. public class Volunteer extends LeiFeng {
  2. public void Sweep(){
  3. System.out.println("志愿者扫地");
  4. }
  5. public void Wash(){
  6. System.out.println("志愿者洗衣服");
  7. }
  8. public void BuyRice(){
  9. System.out.println("志愿者买米");
  10. }
  11. }

测试类:

  1. public class Test {
  2. public static void main(String[] args) {
  3. //创建一个大学生的实例
  4. IFactory factory = new UndergraduateFactory();
  5. Undergraduate student = factory.createLeiFeng();
  6. student.Sweep();
  7. student.Wash();
  8. student.BuyRice();
  9. //创建一个自愿者的实例
  10. IFactory factory2 = new VolunteerFactory();
  11. Volunteer volunteer = factory2.createLeiFeng();
  12. volunteer.Sweep();
  13. volunteer.Wash();
  14. volunteer.BuyRice();
  15. }
  16. }

输出结果:

  1. 大学生扫地
  2. 大学生洗衣服
  3. 大学生买米
  4. 志愿者扫地
  5. 志愿者洗衣服
  6. 志愿者买米




                        <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count"></span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/qq_28055429">
                    <img src="https://profile.csdnimg.cn/C/2/1/3_qq_28055429" class="avatar_pic" username="qq_28055429">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/5.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/qq_28055429" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">Android开始之路</a></span>
                                            </div>
                    <div class="text"><span>发布了52 篇原创文章</span> · <span>获赞 37</span> · <span>访问量 15万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=qq_28055429" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    

    转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51628921

    One----简单工厂模式:

    一,基本知识:

    (1)定义:简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。

    (2)理解:简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    二,实现方法和角色:

    (1)实现方式:简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

    (2)角色和责任:如图:


    工厂(Creator)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。

    工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
    抽象产品(Product)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

    具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

     三,优缺点:

    (1)优点:在于工厂类中包含了必要的逻辑,根据客户需要的条件动态实例化相关的类,

    对客户端来说,去掉了与具体产品的依赖。

    (2)缺点:工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,当增加新的东东时,会违反开放-封闭原则


    四,例子:

    四则运算:简单工厂模式:



    运算类:Operation:

    1. public class Operation {
    2. double numberA = 0;
    3. double numberB = 0;
    4. //两个get方法和set方法
    5. public double getNumberA() {
    6. return numberA;
    7. }
    8. public void setNumberA(double numberA) {
    9. this.numberA = numberA;
    10. }
    11. public double getNumberB() {
    12. return numberB;
    13. }
    14. public void setNumberB(double numberB) {
    15. this.numberB = numberB;
    16. }
    17. //getResult方法
    18. public double getResult() {
    19. double result = 0d;
    20. return result;
    21. }
    22. }
    简单工厂模式类:OperationFactory

    1. /**
    2. * 多肽实现
    3. *
    4. * @author maiyu
    5. *
    6. */
    7. public class OperationFactory {
    8. public static Operation createOperate(String operate) {
    9. Operation oper = null;
    10. switch (operate) {
    11. case "+":
    12. // 向上转型
    13. oper = new NumberAdd();
    14. break;
    15. case "-":
    16. oper = new NumberSub();
    17. break;
    18. case "*":
    19. oper = new NumberMul();
    20. break;
    21. case "/":
    22. oper = new NumberDiv();
    23. break;
    24. default:
    25. break;
    26. }
    27. return oper;
    28. }
    29. }

    四个运算类:

    1. /**
    2. * 加法类,继承父类Operation
    3. *
    4. * @author maiyu
    5. *
    6. */
    7. public class NumberAdd extends Operation {
    8. @Override
    9. public double getResult() {
    10. // 假如某一天公司老板要求在乘法增加一个开根号,即可只需要改动这里
    11. // double result = Math.sqrt(getNumberA() + getNumberB());
    12. double result = getNumberA() + getNumberB();
    13. return result;
    14. }
    15. }

    1. /**
    2. * 减法类,继承父类Operation
    3. *
    4. * @author maiyu
    5. *
    6. */
    7. public class NumberSub extends Operation {
    8. @Override
    9. public double getResult() {
    10. double result = getNumberA() - getNumberB();
    11. return result;
    12. }
    13. }
    1. /**
    2. * 乘法类,继承父类Operation
    3. *
    4. * @author maiyu
    5. *
    6. */
    7. public class NumberMul extends Operation {
    8. @Override
    9. public double getResult() {
    10. double result = getNumberA() * getNumberB();
    11. return result;
    12. }
    13. }

    1. /**
    2. * 除法类,继承父类Operation
    3. *
    4. * @author maiyu
    5. *
    6. */
    7. public class NumberDiv extends Operation {
    8. @Override
    9. public double getResult() {
    10. double result = 0d;
    11. if (getNumberB() != 0) {
    12. result = getNumberA() / getNumberB();
    13. } else {
    14. try {
    15. throw new Exception("除数不能为0");
    16. } catch (Exception e) {
    17. // TODO Auto-generated catch block
    18. e.printStackTrace();
    19. }
    20. // System.out.println("除数不能为0!");
    21. // System.out.println("以下结果是错误的!");
    22. }
    23. return result;
    24. }
    25. }

    客户端:Program

    1. import java.util.Scanner;
    2. /**
    3. * 客户端
    4. * @author maiyu
    5. *
    6. */
    7. public class Program {
    8. public static void main(String[] args) {
    9. try {
    10. // 输入端
    11. Scanner scanner = new Scanner(System.in);
    12. System.out.println("请输入数字A : ");
    13. String numberA = scanner.next();
    14. System.out.println("请输入操作符(+,-,*,/):");
    15. String numberOperation = scanner.next();
    16. System.out.println("请输入数字B : ");
    17. String numberB = scanner.next();
    18. // 在这里调用格式工厂的方法
    19. Operation oper;
    20. oper = OperationFactory.createOperate(numberOperation);
    21. oper.numberA = Double.parseDouble(numberA);
    22. oper.numberB = Double.parseDouble(numberB);
    23. double numberResult = oper.getResult();
    24. // 打印结果
    25. System.out.println("输出结果为:" + numberResult);
    26. } catch (Exception e) {
    27. System.out.println("您的输入有误:");
    28. e.printStackTrace();
    29. }
    30. }
    31. }
    输出:

    1. 请输入数字A :
    2. 8
    3. 请输入操作符(+,-,*,/):
    4. /
    5. 请输入数字B :
    6. 3
    7. 输出结果为:2.6666666666666665
    8. 请输入数字A :
    9. 8
    10. 请输入操作符(+,-,*,/):
    11. /
    12. 请输入数字B :
    13. 0
    14. java.lang.Exception: 除数不能为0
    15. 输出结果为:0.0
    16. at operation.NumberDiv.getResult(NumberDiv.java:16)
    17. at operation.Program.main(Program.java:24)

    但这时,如果客户需求,需要增加求M的N次方的运算,在简单工厂里,就是先增加”求M得N次方“的类,然后去更改工厂方法,

    增加Case语句来判断,但这时岂不是修改了原来的类,违背了开放--封闭原则,,,

    那么这时就要考虑工厂方法模式了,


    TWO-----工厂方法模式

    一,基本知识:

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

    如下图:


    (2) 英文:Factory Method

    二,四个要素:

    工厂接口:工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。


    工厂实现:在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。


    产品接口:产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。


    产品实现:实现产品接口的具体类,决定了产品在客户端中的具体行为。


    三,优点:创建对象的接口,让子类去决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码。工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

    四,理解:如下图,上面那个例子可这样改:



    利用依赖倒置原则,把工厂类抽象出一个接口,里面只有一个创建抽象产品的方法,然后所有的要生成具体类的工厂去实现这个接口,这样:

    一个简单工程模式的工厂类就变成了一个工厂抽象接口和多个具体生成对象的工厂,当我们需要增加例如M的N次方时,就不需要去修改原有的工厂类,只需要增加此功能的运算类和相应的工程类即可。如上图所示。


    下面以一个学雷锋的例子:

    雷锋类:

    1. class LeiFeng {
    2. public void Sweep(){
    3. System.out.println("扫地");
    4. }
    5. public void Wash(){
    6. System.out.println("洗衣服");
    7. }
    8. public void BuyRice(){
    9. System.out.println("买米");
    10. }
    11. }

    工厂接口:

    1. interface IFactory {
    2. LeiFeng createLeiFeng();
    3. }

    大学生工厂:

    1. public class UndergraduateFactory implements IFactory{
    2. @Override
    3. public LeiFeng createLeiFeng() {
    4. return new Undergraduate();
    5. }
    6. }

    志愿者工厂:

    1. public class VolunteerFactory implements IFactory{
    2. @Override
    3. public LeiFeng createLeiFeng() {
    4. return new Volunteer();
    5. }
    6. }

    大学生类:

    1. public class Undergraduate extends LeiFeng {
    2. public void Sweep(){
    3. System.out.println("大学生扫地");
    4. }
    5. public void Wash(){
    6. System.out.println("大学生洗衣服");
    7. }
    8. public void BuyRice(){
    9. System.out.println("大学生买米");
    10. }
    11. }

    志愿者类:

    1. public class Volunteer extends LeiFeng {
    2. public void Sweep(){
    3. System.out.println("志愿者扫地");
    4. }
    5. public void Wash(){
    6. System.out.println("志愿者洗衣服");
    7. }
    8. public void BuyRice(){
    9. System.out.println("志愿者买米");
    10. }
    11. }

    测试类:

    1. public class Test {
    2. public static void main(String[] args) {
    3. //创建一个大学生的实例
    4. IFactory factory = new UndergraduateFactory();
    5. Undergraduate student = factory.createLeiFeng();
    6. student.Sweep();
    7. student.Wash();
    8. student.BuyRice();
    9. //创建一个自愿者的实例
    10. IFactory factory2 = new VolunteerFactory();
    11. Volunteer volunteer = factory2.createLeiFeng();
    12. volunteer.Sweep();
    13. volunteer.Wash();
    14. volunteer.BuyRice();
    15. }
    16. }

    输出结果:

    1. 大学生扫地
    2. 大学生洗衣服
    3. 大学生买米
    4. 志愿者扫地
    5. 志愿者洗衣服
    6. 志愿者买米




    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!