工厂模式
- 工厂模式的作用:实现了创建者和调用者的分离
- 核心本质:
- 实例化对象不使用new,用工厂方法代替
- 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦
- 详细分类:
- 简单(静态)工厂模式:用来生产同一等级结构中的任意产品(对于增加新的产品,需要修改已有代码)
- 工厂方法模式:用来生产同一等级结构中的固定产品(支持增加任意产品)
- 抽象工厂模式:围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
- 满足OOP七大原则中的三个:
- 开闭原则: 一个软件的实体应当对扩展开放,对修改关闭
- 依赖倒转原则: 要针对接口编程,不要针对实现编程
- 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信
- 下面举一个消费者买车的例子
1、不使用工厂
不使用工厂,消费者去买车就要自己去new一辆车,这实际上就是消费者自己去造了一辆车,不符合买车的需求
//车的总接口
package com.wlw.factory;
public interface Car {
void name();
}
//车的实现类
package com.wlw.factory;
public class Wuling implements Car {
@Override
public void name() {
System.out.println("五菱宏光");
}
}
//车的实现类
package com.wlw.factory;
public class Tasla implements Car {
@Override
public void name() {
System.out.println("特斯拉");
}
}
package com.wlw.factory;
public class Consumer {
public static void main(String[] args) {
Car car1 = new Wuling();
Car car2 = new Tasla();
car1.name();//五菱宏光
car2.name();//特斯拉
}
}
2、简单(静态)工厂模式
-
消费者自己不去new车(不用关心车怎么实现的细节),而是通过工厂生产车,减少硬编码。
-
大多数情况下用的都是简单工厂模式,这种模式仍有不足
-
缺点:如以下代码,在简单工厂中已经可以创建五菱宏光和特斯拉两种车,但是如果再增加一辆车,则会修改CarFactory.java的getCar方法,违反了开闭原则,我们应该扩展,不应该去修改一个方法。
-
写一个生产车的工厂,我们只需要传入车的名字,就可以得到这辆车,实现细节交给工厂来处理
package com.wlw.factory;
//静态(简单)工厂模式
public class CarFactory {
public static Car getCar(String name){
if(name == "五菱"){
return new Wuling();
}else if(name == "特斯拉"){
return new Tasla();
}else {
return null;
}
}
}
- 测试
package com.wlw.factory;
public class Consumer {
public static void main(String[] args) {
//1.不使用工厂,消费者自己去new一辆车,实现细节要自己做
//Car car1 = new Wuling();
//Car car2 = new Tasla();
//2.使用简单工厂来生产车,实现细节交给工厂
Car car1 = CarFactory.getCar("五菱");
Car car2 = CarFactory.getCar("特斯拉");
car1.name();//五菱宏光
car2.name();//特斯拉
}
}
3、工厂方法模式
- 我们新建一个CarFactory的接口,然后为每种Car都建一个Factory类。这样就可以使得每次新加入一种车时,只为这种车建立一个对应的工厂就行,不会影响到原来的代码。
- 优点:下次加入一种大众车,(扩展)只需要新建一个 DazhongFactory 就行,不会影响到别的工厂。
- 缺点:代码量加大,管理复杂,结构复杂,编程复杂,实际业务一般使用简单工厂模式
- 根据设计原则,选择工厂方法模式;根据实际业务,选择简单工厂模式
- 总结:不一定要符合设计原则,要根据实际情况加以分析取舍
package com.wlw.factory.factorymethod;
//工厂方法模式
public interface CarFactory {
Car getCar();
}
package com.wlw.factory.factorymethod;
public class WulingFactory implements CarFactory {
@Override
public Car getCar() {
return new Wuling();
}
}
package com.wlw.factory.factorymethod;
public class TaslaFactory implements CarFactory {
@Override
public Car getCar() {
return new Tasla();
}
}
package com.wlw.factory.factorymethod;
public class Consumer {
public static void main(String[] args) {
//1.不使用工厂,消费者自己去new一辆车,实现细节要自己做
//Car car1 = new Wuling();
//Car car2 = new Tasla();
//2.使用简单工厂来生产车,实现细节交给工厂
//Car car1 = CarFactory.getCar("五菱");
//Car car2 = CarFactory.getCar("特斯拉");
//3.方法工厂,为每种Car都建一个Factory类
Car car1 = new WulingFactory().getCar();
Car car2 = new TaslaFactory().getCar();
car1.name();//五菱宏光
car2.name();//特斯拉
}
}
4、抽象工厂模式
- 定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类
- 适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
- 优点:
- 具体产品在应用层的代码隔离,无需关心创建的细节
- 将一个系列的产品统一到一起创建
- 缺点:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难;
- 增加了系统的抽象性和理解难度
4.1、案例
-
可以看到产品分支与工厂分支是独立开来的,产品分支分为多个产品接口,一个产品接口又可以有多个实现类。而工厂分支中的大工厂指定了可以生产哪些产品,其实现类(华为厂商或小米厂商)可以直接new出产品并返回。在测试类中需要某个厂商的某个产品时,直接new出需要的厂商并调用其获取产品的方法。
-
代码结构
package com.wlw.factory.abstract1;
//抽象产品工厂,用来创建具体的产品工厂
public interface ProductFactory {
//手机工厂,用来生产手机
PhoneProduct phoneProduct();
//路由器工厂,用来生产路由器
RouterProduct routerProduct();
}
package com.wlw.factory.abstract1;
//手机产品接口(工厂)
public interface PhoneProduct {
void start();
void shutdown();
void call();
void sendmsg();
}
package com.wlw.factory.abstract1;
//路由器产品接口(工厂)
public interface RouterProduct {
void start();
void shutdown();
void openwifi();
void setting();
}
package com.wlw.factory.abstract1;
//具体的手机产品
public class XiaomiPhone implements PhoneProduct {
@Override
public void start() {
System.out.println("小米手机开机");
}
@Override
public void shutdown() {
System.out.println("小米手机关机");
}
@Override
public void call() {
System.out.println("小米手机打电话");
}
@Override
public void sendmsg() {
System.out.println("小米手机发信息");
}
}
package com.wlw.factory.abstract1;
//具体的手机产品
public class HuaweiPhone implements PhoneProduct {
@Override
public void start() {
System.out.println("华为手机开机");
}
@Override
public void shutdown() {
System.out.println("华为手机关机");
}
@Override
public void call() {
System.out.println("华为手机打电话");
}
@Override
public void sendmsg() {
System.out.println("华为手机发信息");
}
}
package com.wlw.factory.abstract1;
//具体的路由器产品
public class XiaomiRouter implements RouterProduct{
@Override
public void start() {
System.out.println("小米路由器开机");
}
@Override
public void shutdown() {
System.out.println("小米路由器关机");
}
@Override
public void openwifi() {
System.out.println("小米路由器打开wifi");
}
@Override
public void setting() {
System.out.println("小米路由器设置");
}
}
package com.wlw.factory.abstract1;
//具体的路由器产品
public class HuaweiRouter implements RouterProduct{
@Override
public void start() {
System.out.println("华为路由器开机");
}
@Override
public void shutdown() {
System.out.println("华为路由器关机");
}
@Override
public void openwifi() {
System.out.println("华为路由器打开wifi");
}
@Override
public void setting() {
System.out.println("华为路由器设置");
}
}
package com.wlw.factory.abstract1;
//小米工厂来生产小米系列的产品
public class XiaomiProductFactory implements ProductFactory {
//小米手机
@Override
public PhoneProduct phoneProduct() {
return new XiaomiPhone();
}
//小米路由器
@Override
public RouterProduct routerProduct() {
return new XiaomiRouter();
}
}
package com.wlw.factory.abstract1;
//华为工厂来生产华为系列的产品
public class HuaweiProductFactory implements ProductFactory {
//华为手机
@Override
public PhoneProduct phoneProduct() {
return new HuaweiPhone();
}
//华为路由器
@Override
public RouterProduct routerProduct() {
return new HuaweiRouter();
}
}
package com.wlw.factory.abstract1;
public class TestClient {
public static void main(String[] args) {
System.out.println("===================小米系列=================");
//用小米工厂来创建一个手机工厂,在手机工厂里生产小米手机
XiaomiProductFactory xiaomiProductFactory = new XiaomiProductFactory();
PhoneProduct xiaomiphone = xiaomiProductFactory.phoneProduct();
xiaomiphone.start();
//用小米工厂来创建一个路由器工厂,在路由器工厂里生产小米路由器
RouterProduct xiaomirouter = xiaomiProductFactory.routerProduct();
xiaomirouter.start();
System.out.println("===================华为系列=================");
//用华为工厂来创建一个手机工厂,在手机工厂里生产华为手机
HuaweiProductFactory huaweiProductFactory = new HuaweiProductFactory();
PhoneProduct huaweiPhone = huaweiProductFactory.phoneProduct();
huaweiPhone.start();
}
}
/*
===================小米系列=================
小米手机开机
小米路由器开机
===================华为系列=================
华为手机开机
*/
- 该设计模式优缺点:
- 优点:
- 厂商是具有可扩展性的,可有多个厂商去生产手机与路由器
- 厂商可以将一个系列的产品放到一起创建
- 调用者无需关心产品的创建过程,只需要获取工厂即可
- 缺点:
- 如果要生产更多的产品就必须要改动大工厂,厂商也需改动,产品集合被固定了
- 优点:
工厂模式总结
-
小结:
- 简单工厂模式(静态工厂模式)
- 虽然某种程度上不符合设计原则,但实际使用最多!
- 工厂方法模式
- 不修改已有类的前提下,通过增加新的工厂类实现扩展。
- 抽象工厂模式
- 不可以增加产品,可以增加产品族!
- 简单工厂模式(静态工厂模式)
-
应用场景:
- JDK中Calendar的getlInstance方法
- JDBC中的Connection对象的获取
- Spring中IOC容器创建管理bean对象反射中Class对象的newInstance方法