目录
工厂模式也是一个较为简单的设计模式,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
为什么要用工厂模式?
- 解耦:把对象的创建和使用过程分开
- 降低代码重复:如果创建某个类的过程很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多重复代码
- 降低维护成本:由于创建的过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有创建对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本
简单工厂(静态工厂)模式
简单工厂模式只适用很多简单的情况,它违背了开放-封闭原则,每次新添加一个功能,需要在if-else语句中修改,添加分支条件
适用场景:
- 需要创建的对象较少
- 客户不关心对象的创建过程
简单工厂的角色分配:
- 工厂(factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象
- 抽象产品(product)角色:简单工厂锁创建的所有对象的的父类,它负责描述所有实例的公共接口
- 具体产品(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的七大原则:面向接口开放,面向修改关闭。如果要新增一个车,不修改车工厂的代码是无法得到这个车对象的。
可以看出简单工厂模式,可以用来生产同一等级结构中的任意产品
这就是简单工厂的模板弊端,对于新增加的产品,需要修改已有代码
工厂方法模式
工厂方法模式是工厂模式家族中使用的最多的模式,一般项目中 存在最多的就是这个模式
工厂方法模式就是简单工厂的进一步深化,在工厂模式方法中,不再提供一个统一工厂类来创建所有对象,而是针对不同的对象提供不同的工厂,每个对象都有一个与之对应的工厂
适用场景:
- 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
- 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中
工厂方法模式角色分配:
- 抽象工厂角色:工厂方法模式的核心,任何在模式中创建的对象工厂类必须实现这个接口
- 具体工厂角色:实现抽象工厂接口的具体工厂类,包含于应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
- 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- 这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应
具体到造车的例子,我们需要抽象工厂-->车工厂,具体工厂-->宝马车工厂,抽象产品-->车,具体产品-->宝马车
我们想得不同到车,通过简单工厂无法实现了,因为简单工厂没有这个车。
现在的解决方法是,造一个能生产该车的工厂,这是工厂方法模式的思想,也就是变成了这样:
工厂方法模式:
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();
}
}
结果:
小米手机发短信
华为路由开启了