Java设计模式之工厂模式详解

目录

简单工厂(静态工厂)模式

工厂方法模式

抽象工厂模式


工厂模式也是一个较为简单的设计模式,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

为什么要用工厂模式?

  • 解耦:把对象的创建和使用过程分开
  • 降低代码重复:如果创建某个类的过程很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多重复代码
  • 降低维护成本:由于创建的过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有创建对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本

参考:深入理解工厂模式——由对象工厂生成对象

简单工厂(静态工厂)模式

简单工厂模式只适用很多简单的情况,它违背了开放-封闭原则,每次新添加一个功能,需要在if-else语句中修改,添加分支条件

适用场景:

  1. 需要创建的对象较少
  2. 客户不关心对象的创建过程

简单工厂的角色分配:

  1. 工厂(factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象
  2. 抽象产品(product)角色:简单工厂锁创建的所有对象的的父类,它负责描述所有实例的公共接口
  3. 具体产品(concrete product)角色:简单工厂的创建目标,所有创建的对象实例都是充当这个角色的某个具体类的实例

我们通过用造车的例子模拟简单工厂

创建车接口  Car

/**
 * @author Claw
 * @date 2020/7/6 13:35.
 */
public interface Car {
    /**
     * 得到车
     * @return
     */
    Car getCar();
}

创建实现类 BaoMaCar

/**
 * @author Claw
 * @date 2020/7/6 13:36.
 */
public class BaoMaCar implements Car {
    @Override
    public Car getCar() {
        return new BaoMaCar();
    }
}

创建实现类 BaoMaCar

/**
 * @author Claw
 * @date 2020/7/6 13:36.
 */
public class BenchiCar implements Car {
    @Override
    public Car getCar() {
        return new BenchiCar();
    }
}

此时我们需要一个消费者来得到车,是的,我们要买车,这是我们原来的写法,通过new来得到对象。这是我们自己创建的对象,这不是我们想要的结果,我们想要一辆车,并不是要自己造一辆,而是需要联系造车工厂来得到车,车是如何创建,不是消费者需要关心的。


/**
 * @author Claw
 * @date 2020/7/6 13:42.
 */
public class Consumer {
    public static void main(String[] args) {
        BaoMaCar baoMaCar = new BaoMaCar();
        BenchiCar benchiCar = new BenchiCar();
        System.out.println(baoMaCar);
        System.out.println(benchiCar);
    }
}

现在我们使用工厂模式来得到车,需要创建一个车工厂。

/**
 * 车工厂
 * @author Claw
 * @date 2020/7/6 13:45.
 */
public class CarFactory{
    public static Car getCar(String name) {
        if (name.equals("宝马")){
            return new BaoMaCar();
        }else if (name.equals("奔驰")){
            return new BenchiCar();
        }else {
            return null;
        }
    }
}

再次测试:

/**
 * 消费者
 * @author Claw
 * @date 2020/7/6 13:42.
 */
public class Consumer {
    public static void main(String[] args) {
        Car baoMaCar1 = CarFactory.getCar("宝马");
        Car baoMaCar2 = CarFactory.getCar("奔驰");
        System.out.println(baoMaCar1);
        System.out.println(baoMaCar2);
    }
}

但这样做会有个问题,假如我想要其他的车怎么办呢?假如现在我想要大众车,那么再造个大众车来实现Car接口,然后在车工厂里代码里增加一段代码吗?像这样:

但是我们不能这样做,OOP的七大原则:面向接口开放,面向修改关闭。如果要新增一个车,不修改车工厂的代码是无法得到这个车对象的。

可以看出简单工厂模式,可以用来生产同一等级结构中的任意产品

这就是简单工厂的模板弊端,对于新增加的产品,需要修改已有代码

工厂方法模式

工厂方法模式是工厂模式家族中使用的最多的模式,一般项目中 存在最多的就是这个模式

工厂方法模式就是简单工厂的进一步深化,在工厂模式方法中,不再提供一个统一工厂类来创建所有对象,而是针对不同的对象提供不同的工厂,每个对象都有一个与之对应的工厂

适用场景:

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中

工厂方法模式角色分配:

  1. 抽象工厂角色:工厂方法模式的核心,任何在模式中创建的对象工厂类必须实现这个接口
  2. 具体工厂角色:实现抽象工厂接口的具体工厂类,包含于应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
  3. 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  4. 这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应

具体到造车的例子,我们需要抽象工厂-->车工厂,具体工厂-->宝马车工厂,抽象产品-->车,具体产品-->宝马车

我们想得不同到车,通过简单工厂无法实现了,因为简单工厂没有这个车。

现在的解决方法是,造一个能生产该车的工厂,这是工厂方法模式的思想,也就是变成了这样:

工厂方法模式:

CarFactory:抽象工厂,用于得到Car

/**
 * 车工厂
 * @author Claw
 * @date 2020/7/6 13:45.
 */
public interface CarFactory {
    Car getCar();
}

 BaoMaCarFactory:具体工厂,创建BaoMaCar对象实例

/**
 * 宝马车工厂
 * @author Claw
 * @date 2020/7/6 14:51.
 */
public class BaoMaCarFactory  implements  CarFactory{
    @Override
    public Car getCar() {
        return  new BaoMaCar();
    }
}

抽象产品:Car

/**
 * 抽象产品
 * @author Claw
 * @date 2020/7/6 13:35.
 */
public interface Car {
    /**
     * 得到车
     * @return
     */
    Car getCar();
}

 具体产品:BaoMaCar

/**
 * 具体产品
 * @author Claw
 * @date 2020/7/6 13:36.
 */
public class BaoMaCar implements Car {
    @Override
    public Car getCar() {
        return new BaoMaCar();
    }
}

如果需要新增车的类型,那么只需要创建新增车类型,创建新增车类型工厂,消费者来取就好了,这样不存在必须改动代码的问题了。

但这样问题会带来一个问题,就是如果需要的类型越多,工厂类型就越多。

抽象工厂模式

在工厂方法模式中,其实有一个潜在的意识:单纯的造车。

抽象工厂模式是工厂方法的进一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。

比如疫情期间比亚迪工厂制造过口罩,同时它还是会生产车。

适用场景:

  • 和工厂方法一样不需要知道它所创建对象的类
  • 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况(同一个产品族的产品)
  • 系统结构稳定,不会频繁的增加对象

抽象工厂方法模式角色分配:

  • 抽象工厂角色:是工厂方法的核心,任何在模式中创建的对象工厂类必须实现这个接口
  • 具体工厂类角色:实现抽象工厂的具体工厂类,包含与应用程序程序密切相关逻辑,并且受到应用程序调用以创建某一种产品对象。
  • 抽象产品角色:具体工厂创建的抽象产品
  • 具体产品:实现了抽象产品

创建抽象工厂,工厂想要制造什么呢?手机和路由器吧,ok,我们想要造的工厂,是可以造手机,也可以造路由器的。

本次举例中,抽象工厂想生产手机和路由,具体工厂是小米和华为,抽象产品则是手机和路由器,具体产品为小米手机和华为手机,小米和路由和华为路由。

/**
 * 抽象工厂
 * @author Claw
 * @date 2020/7/6 17:27.
 */
public interface AbstractFactory {
    /**
     * 生产手机
     * @return
     */
    PhoneProduct phoneProduct();

    /**
     * 生产路由
     * @return
     */
    RouterProduct routerProduct();
}

 具体工厂类对象:小米工厂和华为工厂,他们都能制造手机和路由器

/**
 * @author Claw
 * @date 2020/7/6 17:44.
 */
public class XiaoMiFactory implements AbstractFactory {
    /**
     * 生产小米手机
     * @return
     */
    @Override
    public PhoneProduct phoneProduct() {
        return new XiaoMiPhone();
    }
    /**
     * 生产小米路由
     * @return
     */
    @Override
    public RouterProduct routerProduct() {
        return new XiaoMiRouter();
    }
}
/**
 * 具体工厂:华为工厂
 * @author Claw
 * @date 2020/7/6 17:51.
 */
public class HuaweiFactory implements AbstractFactory {
    @Override
    public PhoneProduct phoneProduct() {
        return new HuaweiPhone();
    }

    @Override
    public RouterProduct routerProduct() {
        return new HuaweiRouter();
    }
}

抽象产品角色:手机和路由器相应的功能

/**
 * 抽象产品 手机
 * @author Claw
 * @date 2020/7/6 17:29.
 */
public interface PhoneProduct {
    void sendMsg();
    void call();
}
/**
 * 抽象产品 路由
 * @author Claw
 * @date 2020/7/6 17:33.
 */
public interface RouterProduct {
    void start();
    void shutdown();
}

具体产品:小米手机和华为手机

/**
 * 具体产品的实现 :小米手机
 * @author Claw
 * @date 2020/7/6 17:29.
 */
public class XiaoMiPhone implements PhoneProduct {
    @Override
    public void sendMsg() {
        System.out.println("小米手机发短信");
    }

    @Override
    public void call() {
        System.out.println("小米手机打电话");
    }
}
/**
 * 具体产品的实现 :华为手机
 * @author Claw
 * @date 2020/7/6 17:37.
 */
public class HuaweiPhone implements PhoneProduct {
    @Override
    public void sendMsg() {
        System.out.println("华为手机发短信");
    }

    @Override
    public void call() {
        System.out.println("华为手机打电话");
    }
}

具体产品:小米路由和华为路由

/**
 * @author Claw
 * @date 2020/7/6 17:36.
 */
public class XiaoMiRouter implements RouterProduct {
    @Override
    public void start() {
        System.out.println("小米路由开启了");
    }

    @Override
    public void shutdown() {
        System.out.println("小米路由关闭了");
    }
}

测试:

/**
 * @author Claw
 * @date 2020/7/6 17:52.
 */
public class Client {
    public static void main(String[] args) {
        PhoneProduct xiaoMiPhone = new XiaoMiFactory().phoneProduct();
        RouterProduct huaWeiRouter = new HuaweiFactory().routerProduct();
        xiaoMiPhone.sendMsg();
        huaWeiRouter.start();
    }
}

结果: 

小米手机发短信
华为路由开启了

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值