程序员:我终于知道工厂模式是什么了

443 阅读8分钟

Mi作者:千珏

邮箱:wl625363199@gmail.com

公众号:千珏(jue)

标题:设计模式之工厂模式(转载请标明出处)

Hello,各位看官老爷们,千珏我又回来更新了,相信看过前面文章的读者对单例模式应该已经很熟悉了。本来想一天更一篇设计模式的,但是因为最近在肝鸡里奥根本没时间写,吼吼,这真的是一个非常好的鸽的理由。

本章千珏带你们看的是工厂模式,本着由简入繁的原则,所以就优先介绍这个模式了,这是千珏认为第二好理解的设计模式,正是因为太简单了,所以不怎么能生动形象的讲出来,毕竟越简单的越难讲,我尽量的根据生活里面的例子来配合讲解。

工厂模式分类

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

什么是简单工厂模式

定义

简单工厂模式属于创建型模式又叫做静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。 简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类

定义中最重要的一句话就是:专门定义一个目标类来负责创建其他类的实例,这个千珏会在下面通过生活中的例子来介绍。

比如表弟去面试的时候

表弟:你好,我是表弟。

面试官:千珏,你好,你能用代码写个简单的计算器吗。

表弟:可以啊(内心os:蛤,这个面试官也太看不起我了吧)

然后千珏就给出了下列的代码。

public class Calculator{
    public static void main(String []args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入数字a");
        double a = scan.nextDouble();
        System.out.println("请输入数据b");
        double b = scan.nextDouble();
        System.out.println("请输入运算符号 + - * /");
        String operator = scan.next();
        double result = 0;
        if(operator.equals("+")){
            result = a + b;
        }else if(operator.equals("-")){
            result = a - b;
        }else if(operator.equals("*")){
            result = a * b;
        }else if(operator.equals("/")){
            if(b == 0){
               System.out.println("被除数b不能为零,程序出错");
               System.exit(0);
            }else{
               result = a / b;
            }
        }else{
            System.out.println("结果出错");
            System.exit(0);
        }
        System.out.println(a + " + "  + operator + " " + b + " = " + result );
    }
}

写完上面这个代码给面试官看之后。

表弟:面试官你看上面这个程序就实现了简单的计算器的功能。

面试官;嗯,写的可以但还是有点欠缺,你回去等通知吧。

表弟上面的代码写的虽然功能是实现了,但是这个程序根本没有办法复用,如果我要是想添加一个开根运算的功能,那就要改上面的代码了,所以我要是面试官我肯定也不让表弟通过。

面试官其实想考表弟的是工厂模式,下面让千珏来带你们看一下,面试官想看到的代码,希望在座的各位看官在去面试的时候都别犯了和表弟一样的错误。

//运算方法接口
public interface IOperation{
    public double operation(double a, double b);
}
//具体的运算类
public class OperationAdd implements IOperation{
    public double operation(double a,double b){
        return a + b;
    }
}
public class OperationSub implements IOperation{
    public double operation(double a,double b){
        return a - b;
    }
}
public class OperationMul implements IOperation{
    public double operation(double a,double b){
        return a * b;
    }
}
public class OperationDiv implements IOperation{
    public double operation(double a,double b){
        if(b == 0){
            throws Exception("被除数不能为零");
        }
        return a / b;
    }
}
//工厂类
public class OperationFactory{
    private OperationFactory{}
    public static IOperation createrOperation(String name){
        if(name == null){
            return null;
        }
        if(name.equals("+")){
            return new OperationAdd();
        }else if(name.equals("-")){
            return new OperationSub();
        }else if(name.equals("*")){
            return new OperationMul();
        }else if(name.equals("/")){
            return new OperationDiv();
        }else{
            return null;
        }
    }
}
//测试类
public class TestOperation{
    public static void main(String []args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入数字a");
        double a = scan.nextDouble();
        System.out.println("请输入数据b");
        double b = scan.nextDouble();
        System.out.println("请输入运算符号 + - * /");
        String oper = scan.nextLine();
        IOperation operation = OperationFactory.createOperation();
        System.out.println(a + " "  + oper + " " + b + " = " + operation.operation(a,b));
    }
}

如果你要写出上面的代码那么简单工厂模式你已经掌握了精髓了,上述的代码如果你要修改加法运算的逻辑,直接在加法运算类的方法里面修改就好了,不用修改主代码里面的程序,完美解耦了。如果你要添加别的运算符的话,那么你添加对应的运算子类,在运算工厂里面给他再添加个判断分支可以就行了,但是这种模式还有点问题,下面我会讲解一下他的问题。

什么是工厂方法模式

定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂就去使一个类的实例化延迟到其子类。

先来把上面的例子用工厂方法改写一下

//工厂方法接口
public interface OperationFactory{
  IOperation createrOperation();   
}
//具体工厂
public class AddFactory implements OperationFactory{
    public IOperation createrOperation(){
        return new OperationAdd();
    }
}
public class SubFactory implements OperationFactory{
    public IOperation createrOperation(){
        return new OperationSub();
    }
}
public class MulFactory implements OperationFactory{
    public IOperation createrOperation(){
        return new OperationMul();
    }
}
public class DivFactory implements OperationFactory{
    public IOperation createrOperation(){
        return new OperationDiv();
    }
}
//测试类
public class TestOperation{
    public static void main(String []args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入数字a");
        double a = scan.nextDouble();
        System.out.println("请输入数据b");
        double b = scan.nextDouble();
        OperationFactory operationFactory = new AddFactory();
        IOperation operation = operationFactory.createrOperation();
        System.out.println(a + " + " + b + " = " + operation.operation(a,b));
    }
}

看到这里相信有些看官老爷就会问到千珏了。

看官老爷:千珏,在以前的简单工厂模式中我如果要加个新的运算方法,我只要加个功能类,再去工厂方法里面添加个判断分支不就行了,但是现在用了工厂方法,要加个功能类,还要加个相关的工厂类,还要去更改客户端,这不是增加了很多类和方法,增加了复杂性,为什么我们不直接用简单工厂模式呢?

千珏:这个问题看官老爷看的很仔细呀,这个正是简单工厂模式和工厂方法模式的区别。以前如果我们要添加一个新的运算符方法,我们是必须修改运算工厂类里面的方法的,就修改了原有的类,这样我们不但对扩展开放了,对修改也开放了,这样就违背了开闭原则 ,于是这个时候工厂方法就来了,解决了上面简单工厂的问题。

如果看官老爷看的仔细的话就会发现千珏在上面说过一句话,虽然简单工厂模式虽好但是还有点问题,没错就是违背了开闭原则,而工厂方法模式出现了就很容易的解决了简单工厂模式的问题。

什么是抽象工厂模式

定义

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

看这个定义你们会觉得很懵逼,看下面的例子你们就会觉得这个抽象工厂模式其实也没有那么难。

比如我们是小米公司,现在我们要生产手机、微波炉、空调。

这个时候我们会写出的代码就是这个样子的

//手机接口
public interface Phone{
    String createPhone();
}
//微波炉接口
public interface Micro{
    String createMircro();
}
//空调接口
public interface Aircond{
    String createAircond();
}
//具体产品类
public XiaomiPhone implements Phone{
    public String createPhone(){
        return "小米手机";  
    }
}
public XiaomiMicro implements Micro{
    public String createMircro(){
        return "小米微波炉"; 
    }
}
public XiaomiAircond implements Aircond{
    public String createAircond(){
        return "小米空调";
    }
}

如果我们要用工厂方法模式来写这个例子是不是就还要添加手机工厂、微波炉工厂、空调工厂,如果 这个时候我们还有别的家公司也要生产手机、微波炉、空调,那我们是不是还要多建几个实例,这个时候就需要用到我们抽象工厂方法模式了。

比如格力公司这个时候也要来生产手机、微波炉、空调,代码如下。

//具体产品类
public GeliPhone implements Phone{
    public String createPhone(){
        return "格力手机";  
    }
}
public GeliMicro implements Micro{
    public String createMircro(){
        return "格力微波炉"; 
    }
}
public GeliAircond implements Aircond{
    public String createAircond(){
        return "格力空调";
    }
}
//抽象工厂接口
public interface Creator{
    Phone createPhone();
    Mircro createMircro();
    AirCond createAirCond();
}
//小米具体工厂
public class XiaomiFactory implements Creator{
    public Phone createPhone(){
        return new XiaomiPhone();
    }
    public Mircro createMircro(){
        return new XiaomiMircro();
    }
    public AirCond createAirCond(){
        return new XiaomiAirCond();
    }
}
//格力具体工厂
public class GeliFactory implements Creator{
    public Phone createPhone(){
        return new GeliPhone();
    }
    public Mircro createMircro(){
        return new GeliMircro();
    }
    public AirCond createAirCond(){
        return new GeliAirCond();
    }
}
//测试
public class TestFactory{
    public static void main(String []args){
        //生产小米公司产品
        Creator creator = new XiaomiFactory();
        String phone = creator.createPhone().createPhone();
        String mircro = creator.createMircro().createMircro();
        String airCond= creator.createAirCond().createAirCond();
        //生产格力公司产品
        creator = new GeliFactory();
        phone = creator.createPhone().createPhone();
        mircro = creator.createMircro().createMircro();
        airCond= creator.createAirCond().createAirCond();
    } 
}

通过上面的代码可以看出来抽象工厂模式比工厂方法模式在有多个产品的情况下,用起来比较简洁(虽然我没有用工厂方法实现上面的例子,但是各位看官老爷看我上面的文章应该还是能自己写出来工厂方法实现上面例子的代码吧)

希望各位看官老爷看到这里能对这三种模式能有一些新的理解并且可以灵活的应用这样千珏的目的就达到了。

总结

这期千珏介绍了工厂模式的三种类型,即简单工厂模式、工厂方法模式、抽象工厂模式,希望各位看官老爷看完这篇文章对这工厂模式肯定有了新的理解 。

首先我们从简单工厂模式到了工厂方法模式是因为简单工厂模式违背了开闭原则 ,所以出现了工厂方法模式,从工厂方法模式到了抽象工厂模式,是因为抽象工厂模式弥补了工厂方法模式中只能创建一个系列产品的问题。

你们可以自己尝试着用工厂方法来实现我上面最后一个例子看看。

最后感谢大家的观看,如果各位看官老爷觉得千珏写的好的可以给千珏点个关注,也欢迎大家来微信找我玩哦,微信搜索千珏(jue)。

在这里插入图片描述

下期预告:观察者模式。