简单工厂模式

来源:互联网 发布:穆斯林党员 知乎 编辑:程序博客网 时间:2024/06/15 21:20

还是拿《大话设计模式》里面的例子来说,设计一个计算器,能够计算加减乘除。根据面向对象的思想(第一个demo只用到了封装,后面一个用到了封装、继承、多态),我们可以抽取一个计算类能根据输入的数字a,运算符,数字b进行运算。

public class Operation {    /**     * 进行加减乘除运算     */    public static double operate(int numberA,int numberB,String symbol){        double result = 0;        switch (symbol) {        case "+":            result = numberA + numberB;            break;        case "-":            result = numberA - numberB;            break;        case "*":            result = numberA * numberB;            break;        case "/":            result = numberA / numberB;            break;        default:            break;        }        return result;    }}

客户端代码

public class Client {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入运算:");        String line = scanner.nextLine();        String[] strs = line.split(" ");        double result = Operation.operate(Integer.parseInt(strs[0]), Integer.parseInt(strs[2]),                strs[1]);        System.out.println("计算结果:" + result);        scanner.close();//      请输入运算,空格分开://          3 + 5//          计算结果:8.0    }}

但是如果哪一天要修改计算的加法呢,或者增加求与运算,那么不就得修改Operation类吗,而实际我们只需要修改一个运算,决不能影响其他运算,甚至应该是个个运算相互隔离不知道对方的存在,否则修改时可能不小心对其他运算造成影响。
所以我们可以分离出4个类(加减乘除运算类)都继承自同一个运算类,各司其职。

public abstract class Operation {    protected int numberA;    protected int numberB;    public abstract double operate();    getset方法}
/** * 加法运算类 * @author 12706 * */public class AddOperation extends Operation{    @Override    public double operate() {        System.out.println("正在进行加法运算...");        double result= numberA+numberB;        return result;    }}
/** * 减法运算类 * @author 12706 * */public class SubOperation extends Operation{    @Override    public double operate() {        System.out.println("正在进行减法运算...");        return numberA-numberB;    }}
/** * 乘法运算类 * @author 12706 * */public class MulOperation extends Operation{    @Override    public double operate() {        System.out.println("正在进行乘法运算...");        return numberA*numberB;    }}
/** * 除法运算类 * @author 12706 */public class DivOperation extends Operation{    //只取小数点前面    @Override    public double operate() {        if (numberB == 0){            throw new RuntimeException("被除数不能为0");        }        //BigDecimal decimal = new BigDecimal(numberA).divide(new BigDecimal(numberB));        System.out.println("正在进行除法运算...");        return numberA/numberB;    }}

客户端代码

public class Client {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        //要求不能乱输        System.out.println("请输入运算,空格分开:");        String line = scanner.nextLine();        String[] strs = line.split(" ");        Operation operation = null;        //判断实例化谁        switch (strs[1]) {        case "+":            operation = new AddOperation();            break;        case "-":            operation = new SubOperation();            break;        case "*":            operation = new MulOperation();            break;        case "/":            operation = new DivOperation();            break;        default:            break;        }        operation.setNumberA(Integer.parseInt(strs[0]));        operation.setNumberB(Integer.parseInt(strs[2]));        System.out.println("计算结果:" + operation.operate());        scanner.close();    }}

但是到这里又得考虑一点,实例化哪个运算类这里成了客户端判断,客户端应该负责给运算而不应该做判断啊,所以实例由谁创建就可以引出简单工厂模式了。
到底由谁创建对象,只需要客户端给出运算符,工厂会给我们返回要创建的对象。

public class OperationFactory {    /**     * 根据运算符返回对应对象     * @param symbol 运算符     * @return     */    public static Operation getOperation(String symbol){        Operation operation = null;        switch (symbol) {        case "+":            operation = new AddOperation();            break;        case "-":            operation = new SubOperation();            break;        case "*":            operation = new MulOperation();            break;        case "/":            operation = new DivOperation();            break;        default:            break;        }        return operation;    }}

客户端代码

public class Client {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        //要求不能乱输        System.out.println("请输入运算,空格分开:");        String line = scanner.nextLine();        String[] strs = line.split(" ");        //根据运算符获取需要的对象        Operation operation = OperationFactory.getOperation(strs[1]);        operation.setNumberA(Integer.parseInt(strs[0]));        operation.setNumberB(Integer.parseInt(strs[2]));        double res = operation.operate();        System.out.println(res);        scanner.close();    }}

为了理解更清晰下面给出老公爱红牛的例子。工厂生产汽车的例子

public interface Car {    public void introduce();}
public class FordCar implements Car{    @Override    public void introduce() {        System.out.println("我是福特...");    }}
public class HondaCar implements Car{    @Override    public void introduce() {        System.out.println("我是东风...");    }}
    public class BenzCar implements Car{        @Override        public void introduce() {            System.out.println("我是奔驰...");        }    }

工厂类,根据品牌名生产汽车
这里用if实现(跟which一样)

public class CarFactory {    public static Car getInstance(String brand){        if(brand.equals("benz")){            return new BenzCar();        }else if (brand.equals("honda")) {            return new HondaCar();        }else if (brand.equals("ford")) {            return new FordCar();        }else {            return new HondaCar();        }    }}

客户端代码

public class Client {    public static void main(String[] args) {        Car ford = CarFactory.getInstance("ford");        ford.introduce();        Car honda = CarFactory.getInstance("honda");        honda.introduce();        Car benz = CarFactory.getInstance("benz");        benz.introduce();    }}

输出

我是福特...我是东风...我是奔驰...

注:其实能看到简单工厂模式是有明显的不足的,因为如果增加了汽车类那我们还得继续else if判断,那就是要修改原来的代码了,虽然不影响原来的汽车类,但是根本不满足开发-封闭原则不易于维护拓展。后面会介绍使用反射来解决这个问题。下面先给出反射用的代码吧

public class CarFoctory2 {    //不让别人创建对象    private CarFoctory2(){}    private static Properties config = new Properties();    static{        try {            config.load(CarFoctory2.class.getResourceAsStream("car.properties"));        } catch (Exception e) {            e.printStackTrace();            throw new RuntimeException(e);        }    }    public static Car newCar() throws Exception{        String className = config.getProperty("Car");        Class clazz = Class.forName(className);        //局限性:要求该类有无参的构造方法,所以有了抽象工厂方法        Car car = (Car)clazz.newInstance();        return car;    }}

配置文件car.properties内容如下
根据需要来改变配置文件的Car类

Car=com.scu.design2.simplefactory.FordCar
原创粉丝点击