设计模式之---简单工厂模式

  • 简述##

    工厂,顾名思义:通过对原材料进行不同的加工来生产不同的品。设计模式里面的简单工厂模式也类似。通过传入的参数来对应创造不同的实例(这些不同实例是属于同一个继承链上的) ,然后返回一个基类的引用(或者指针)。

  • 举例

    书读千遍不如实践一次,看着书上的说明好像懂了,但是实际上在自己写程序的时候就混淆或者忘记了。说白了还是不懂,没能把学到的知识结合现实的例子来结合。

    这里我举两个我自己想到的例子作为说明跟大家分享一下。
    第一个,简易计算器的实现。功能包括加、减、乘、除。
    第二个,企业工资计算。企业不同职工工资计算方法是不一样的。从底层工人,到蓝领,白领,金领都不一样。

    一般来说,这两个例子编程实现起来都相当简单,甚至于我都不想在这里写出来了,包括我之前还没看设计模式的时候,我也是一看了题目就写了代码。因为之前求的是方便,一个简易的计算器,一般来说就从UI层取得计算类型,在代码块中直接’if()\else()’就搞定了。同样来说,企业工资计算也是一样。如果需求不变,运算类型或者职工工种不多的情况下可以这样写,因为简单粗暴。

    但是问题是,一旦面临着需求不断变化和类型比较多的情况下,那么上面说的代码就直接是不能用了。我们之前学习面向对象的时候,书上一直强调,三大特性:继承,封装,多态。又说了,一个好的项目或者程序,是要求:易维护、可复用、可扩展、灵活性好。我对它们的理解是:

    易维护:要改就只改需要改的地方,各部分耦合度低。()
    可复用:代码在各处都能重复使用,有普适性。(封装、模块化)
    可扩展:如果需要增加功能,那么尽量在不修改已有代码的情况下。(继承,多态)
    灵活性好:通过不同的组合对象、方法,得到不同的功能。(比如装饰模式)
    设计模式就是运用面向对象的三大特性:继承、多态、封装,来达到程序的易维护、可复用、可扩展、灵活性好的要求。
    因此,我们需要学习设计模式。对于上面的两个问题,可以采用简单工厂、策略、工厂模式来实现。现在,采用简单工厂模式,因为它最简单易懂。

  • 分析

    既然是面向对象,那么我们就需要运用抽象的思维分析。上面举的两个列子,都有一个共同点,他们都属于同一个业务(或者范畴)。计算器中加、减、乘、除都是属于不同运算类型,但是他们有共同点:参数都是两个,目的都是求出结果;企业工资计算中,不同职工虽然工资计算方式不一样,但是他们的基本信息组成都一样:姓名,学历,基本工资,奖金,出勤率等。因此,他们其实只是实现的方式不一样而已,输入和输出其实都是一样的。

    对于计算器,我们可以建立一个运算模板类作为基类,积累提供模板函数和基本属性(运算参数),衍生出加、减、乘、除四个类;一个工厂类作为生产这些类的地方。这样,一个简单工厂模式就出来了。以后如果是哪个运算出问题了,就只要针对哪个类修改就行了;需要加运算,就从模板类再派生一个类就行了;同时运算类的代码到哪里都能够使用;这样,不管有多少种运算类别,都能够很容易解决了。

UML图如下:

*UML图如下:*

一般来说我们一般软件设计采用的方式都是三层架构,分为界面、业务逻辑、数据库访问层;这里由于没有牵扯到数据库,所以就简单分为界面和业务层。结合三层架构,使用工厂模式,我们把计算的过程与界面给分开,把耦合度给降低了。而且这样的逻辑让人一目了然,要增加运算类型只要继承Operator类,然后在工厂类那边增加一个返回实例的代码段就行了。总之呢,方便、简洁,我们写程序最终目的不是完成一个程序,而是完成一个良好的程序。

下面我附上的java实现代码:

package com.malingyi.operator;

import java.util.Scanner;

/**
 * UI层,与用户交互的界面
 * @author David
 *
 */
public class MainUI {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
    double mNumA;
    double mNumB;
    int type;
    Scanner scanner = new Scanner(System.in);
    System.out.println("请选择运算类型:\n1:加法      2:减法     3:乘法     4:除法");
    type = scanner.nextInt();
    System.out.println("请输入第一个参数:");
    mNumA = scanner.nextDouble();
    System.out.println("请输入第二个参数:");
    mNumB = scanner.nextDouble();

    Operator operator = Factory.getOprator(type);
    operator.setNumA(mNumA);
    operator.setNumB(mNumB);
    System.out.println("结果是:"+operator.getResult());
    }

}
/**
*下面的是业务逻辑层,封装业务逻辑
*/
package com.malingyi.operator;

/**
 * 运算基类
 * @author David
 *
 */
public class Operator {
   private double mNumA;
   private double mNumB;

   public void setNumA(double numA){
       mNumA = numA;
   }
   public void setNumB(double numB){
       mNumB = numB;
   }
   public double getNumA(){
       return mNumA;
   }
   public double getNumB(){
       return mNumB;
   }
   /**
    * 计算结果模板
    * @return 默认基类返回的结果为 0
 * @throws Exception 
    */
   public double getResult() throws Exception{
       double result = 0;
       return result;
   }

}

package com.malingyi.operator;
/**
 * 加法运算类
 * @author David
 *
 */
public class OperationAdd extends Operator {

    @Override
    public double getResult() {
        // TODO Auto-generated method stub
        double result = 0;
        result = getNumA()+getNumB();
        return result;
    }

}
package com.malingyi.operator;

/**
 * 减法运算类
 * @author David
 *
 */
public class OperationSub extends Operator {

    @Override
    public double getResult() throws Exception {
        // TODO Auto-generated method stub
        double result = 0;
        result = getNumA()-getNumB();
        return result;
    }  
}


package com.malingyi.operator;

/**
 * 除法运算类
 * @author David
 *
 */
public class OperationDiv extends Operator {

    @Override
    public double getResult() throws Exception {
        // TODO Auto-generated method stub
        double result = 0;
        try {
            if(getNumB() == 0){
                throw new Exception("除数不能为零");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        result = getNumA()/getNumB();
        return result;
    }

}
package com.malingyi.operator;
/**
 * 乘法运算类
 * @author David
 *
 */
public class OperationMul extends Operator {

    @Override
    public double getResult() {
        // TODO Auto-generated method stub
        double result = 0;
        result = getNumA()*getNumB();
        return result;
    }  
}

package com.malingyi.operator;
/**
 * 简单工厂类,根据传来的运算类型,产出相应的运算实例
 * @author David
 *
 */
public class Factory {
    public static final int ADD = 1;
    public static final int SUB = 2;
    public static final int MUL = 3;
    public static final int DIV = 4;
    /**
     * 静态类,用来获取具体运算类
     * @param type 运算类的类型。
     * @return 与参数对应的运算类类型,如果不存在则返回null
     */
    public static Operator getOprator(int type) {
        switch (type) {
        case ADD:
            return new OperationAdd();
        case SUB:
            return new OperationSub();
        case MUL:
            return new OperationMul();
        case DIV:
            return new OperationDiv();
        default:
            break;
        }
        return null;
    }
}
  • 总结

    上面这个例子讲的是计算器的问题,其实企业工资计算也是一样的。这里就不提供UML图和代码了。我的总结就是,简单工厂模式运用了多态、继承、封装,实现了将UI和后台业务逻辑分开,简化开难度。如果几个功能或者业务能够抽象出相同的目标和方法,那么就可以使用简单工厂模式来将具体实现和前台UI分开,降低耦合度。

    设计模式也不仅仅是这一种,反正目的就是简化开发难度,达到易维护、可扩展、可复用、灵活性好的目的,量体裁衣才是最好的做法。现在正在学习当中,觉得受益匪浅,所以跟大家分享一下。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值