设计模式之---工厂模式、建造者模式


☺ 对于工厂模式,个人学习需要掌握

  • 注意答案的重点标黑了。对于工厂模式、建造者模式,掌握,我下面这几点就很棒棒。

一、工厂模式

1、什么是工厂模式:【关键字factory

答:创建对象时,不直接new,而是交由一个工厂类/工厂接口的工厂方法负责创建。

2、工厂模式的意义

答:将实例化对象的代码提取出来,放到一个类(工厂类)中统一管理和维护;实现了创建者和调用者的分离,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。

3、工厂模式包括哪三种

答:简单工厂模式、工厂方法模式、抽象工厂模式

4、工厂模式的使用对比[简单工厂模式和工厂方法模式对比]:

答:简单工厂模式:虽然某种程度上不符合设计原则,但实际使用最多工厂方法模式:不修改已有类的前提下,通过增加新的工厂类实现扩展;抽象工厂模式:不可以增加产品,可以增加产品族。

★ 虽然简单工厂模式不符合理论中的开闭原则,但是工厂方法模式定义的大量子类工厂实现类,管理也非常麻烦,实际开发中使用的最多是简单工厂模式.

5、抽象工厂是什么

答:是工厂的工厂,超级工厂。适合生产一个稳定的产品族采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可

6、工厂模式的应用场景:

  • jdk中calendar的getInstance方法----简单工厂模式
  • JDBC中的Connection对象的获取
  • Spring中的IOC容器创建管理bean对象
  • 反射中Class对象的newInstance方法

二、建造者模式

1、什么是建造者模式:【关键字builder

答:又叫生成器模式,是一种对象构建模式。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

2、四种角色是什么

答:

(1) Product(产品角色):一个具体的产品对象

(2) Builder(抽象建造者): 创建一个产品对象的各个部件的接口/抽象类

(3) ConcreteBuilder(具体建造者): 实现或继承抽象建造者接口,具体地构建和装配各个部件

(4) Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。负责指挥构建一个工程,决定了工程如何构建,按照什么顺序构建。

举例:建造房子:

需要建房子:这一过程为打桩、砌墙、封顶。不管是普通房子也好,别墅也好都 需要经历这些过程,下面我们使用建造者模式(Builder Pattern)来完成.

1、产品角色:Product-房子,定义了房子的属性

2、抽象建造者:Builder-抽象的工人,定义了一些建造房子组件的方法和接口

3、具体建造者:ConcreteBuilder-具体的工人,实现了建造房子组件

4、指挥者:Director-房子的指挥设计者,:负责指挥构建一个工程,决定了工程如何构建,按照什么顺序构建

3、建造者模式在JDK的应用和源码分析 (java.lang.StringBuilder中的建造者模式)

答:源码中建造者模式角色分析:

(1) Appendable接口是抽象建造者, 定义了抽象方法,定义了多个append方法(抽象方法)

(2) AbstractStringBuilder抽象类,实现了 Appendable接口方法AbstractStringBuilder 是建造者,只是不能实例化

(3)StringBuilder 继承了AbstractStringBuilder,即充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由 AbstractStringBuilder 完成, 而StringBuilder 继承了 AbstractStringBuilder

4、建造者模式的优缺点:

答:优点:(1) 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节;

    (2) **用户使用不同的具体建造者即可得到不同的产品对象**;

    (3) **增加新的具体建造者无需修改原有类库代码,符合“开闭原则”**

缺点:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式

5、抽象工厂模式VS建造者模式

答:抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品采用抽象工厂模式不需要关心构建过程,只关心什么产品 由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。



一、工厂设计模式

1、作用和意义:实现了创建者和调用者的分离

★ 工厂模式的意义:将实例化对象的代码提取出来,放到一个类(工厂类)中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。


2、三种工厂模式:

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


3、 设计模式的依赖抽象原则:

 创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中,并返回。

 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)

 不要覆盖基类中已经实现的方法


4、核心本质:

实例化对象不使用new,用工厂方法代替 factory
将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦



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

用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有代码)

★ 对于简单工厂模式的举例:消费者买车

情况一:在没有使用简单工厂模式下,消费者(Consumer类)要买车,需要自己 new来构建一辆自己想要买的车。【需要消费者自己制作车 (new 构建 车对象),则消费者是需要车的内部细节,才能new出车对象】

情况二:使用简单工厂模式下,消费者只需要调用汽车工厂(CarFactory类)的获取车的方法,就可以买车了,不用关系车的创建的各种细节。而汽车工厂(CarFactory类)作用就是来制作车 (new 构建 车对象)的,并为外界提供获取车对象的方法。

public class Consumer {
    public static void main(String[] args) {
        // 1、没有使用简单工厂模式的情况:
        // Car car = new WuLing();
        // Car car1 = new Tesla();

        // 2、使用工厂创建
        Car car = CarFactory.getCar("wuling");
        Car car1 = CarFactory.getCar("tesila");

        car.name();
        car1.name();
    }
}


public interface Car {
    void name();
}

public class WuLing implements Car{

    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}

public class Tesla implements Car{

    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}

// 静态工厂模式
// 开闭原则
public class CarFactory {

    // 方法一: 不满足开闭原则
    public static Car getCar(String car){
        if(car.equals("wuling")){
            return new WuLing();
        }else if(car.equals("tesila")){
            return new Tesla();
        }else {
            return null;
        }
    }

    // 方法二:
    public static Car geyWuling(){
        return new WuLing();
    }
    public static Car geyTesla(){
        return new Tesla();
    }


}
图片.png

□ 弊端:增加一个新的产品,做不到不修改代码。

例如:扩展一个大众的汽车,则需要修改工厂类(CarFactory)的Car(String car)方法的代码,不符合开闭原则【对扩展开发,对修改关闭】。

  • 解决:工厂方法模式


■ 工厂方法模式:

用来生产同一等级结构中的固定产品(支持增加任意产品)

public class Consumer {
    public static void main(String[] args) {
        Car car = new WulingFactory().getCar();
        Car car1 = new TeslaFactory().getCar();

        car.name();
        car1.name();

        Car car2 = new MoBaiFactory().getCar();
        car2.name();
    }
}



public interface Car {
    void name();
}

public class WuLing implements Car {

    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}

public class Tesla implements Car {

    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}

// 工厂方法模式
public interface CarFactory {
    Car getCar();
}

public class WulingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new WuLing();
    }
}

public class TeslaFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Tesla();
    }
}

图片.png


■ 工厂方法模式:通过将简单工厂模式原先的工厂类抽象成接口,然后根据车的种类,决定了抽象工厂接口的子类工厂实现类,并在子类工厂实现类内创建对应车种类的对象。

  • 举例:现在多了一个车的品牌,叫宝马,相应的车工厂就有宝马工厂(实现工厂接口),在宝马车工厂实现了制作宝马车的方法。


3、理论和实际应用对比【对比简单工厂模式和工厂方法模式】

1、结构复杂度:simple>method

2、代码复杂度:simple>method

3、编程复杂度:simple>method

4、管理上的复杂度:simple>method

★ 虽然简单工厂模式不符合理论中的开闭原则,但是工厂方法模式定义的大量子类工厂实现类,管理也非常麻烦,实际开发中使用的最多是简单工厂模式



4、抽象工厂模式:"工厂的工厂,超级工厂。适合生产一个稳定的产品族"

围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂

(1) 定义:

抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定他们的具体的类(针对整个产品族,产品等级数量相对固定的产品族)

(2) 适用场景:

  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
  • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体实现
图片.png

■ 抽象工厂模式-其实就是工厂方法模式的抽象,体现在将原先的工厂定义为超级工厂接口,且包含的属性成员也是接口。

1、定义一个超级工厂接口IProductFactory:包含两个产品接口(接口属性成员)-手机产品接口IphoneProduct、路由器产品接口IRouterProduct 【产品族

2、然后超级工厂接口有具体的实现子类-小米工厂XiaomiFactory、华为工厂HuaweiFactory

3、对于超级工厂接口定义的接口属性成员有对应的实现子类

  • 然后手机产品接口IphoneProduct有具体的实现子类-小米手机实现子类XiaomiPhone、华为手机实现子类HuaweiPhone

  • 同样路由器产品接口IRouterProduct 也有具体的实现子类-小米路由实现子类XiaomiRouter、华为路由实现子类HuaweiRouter

// 手机产品接口
public interface IphoneProduct {

    void start();
    void shutdown();
    void callup();
    void sendSMS();
}

// 小米手机
public class XiaomiPhone implements IphoneProduct{
    @Override
    public void start() {
        System.out.println("开启小米手机");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭小米手机");
    }

    @Override
    public void callup() {
        System.out.println("小米手机打电话");
    }

    @Override
    public void sendSMS() {
        System.out.println("小米手机发短信");
    }
}


// 华为手机
public class HuaweiPhone implements IphoneProduct{
    @Override
    public void start() {
        System.out.println("开启华为手机");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭华为手机");
    }

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

    @Override
    public void sendSMS() {
        System.out.println("华为手机发短信");
    }
}

// 路由器产品接口
public interface IRouterProduct {

    void start();
    void shutdown();
    void openWifi();
    void setting();
}

// 小米路由器
public class XiaomiRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("启动小米路由器");
    }

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

    @Override
    public void openWifi() {
        System.out.println("打开小米Wi-Fi");
    }

    @Override
    public void setting() {
        System.out.println("小米设置");
    }
}

// 华为路由器
public class HuaweiRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("启动华为路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭华为路由器");
    }

    @Override
    public void openWifi() {
        System.out.println("打开华为Wi-Fi");
    }

    @Override
    public void setting() {
        System.out.println("华为设置");
    }
}

// 抽象产品工厂
public interface IProductFactory {

    // 生产手机
    IphoneProduct iphoneProduct();

    // 生产路由器
    IRouterProduct irouterProduct();

}

public class XiaomiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneProduct() {
        return new XiaomiPhone();
    }

    @Override
    public IRouterProduct irouterProduct() {
        return new XiaomiRouter();
    }
}

public class HuaweiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneProduct() {
        return new HuaweiPhone();
    }

    @Override
    public IRouterProduct irouterProduct() {
        return new HuaweiRouter();
    }
}

public class Client {
    public static void main(String[] args) {
        System.out.println("小米系列产品--------------------");
        // 小米工厂
        XiaomiFactory xiaomiFactory = new XiaomiFactory();

        IphoneProduct iphoneProduct = xiaomiFactory.iphoneProduct();
        iphoneProduct.callup();
        iphoneProduct.sendSMS();

        IRouterProduct iRouterProduct = xiaomiFactory.irouterProduct();
        iRouterProduct.openWifi();

        System.out.println("华为系列产品--------------------");
        // 小米工厂
        HuaweiFactory huaweiFactory = new HuaweiFactory();

        iphoneProduct = huaweiFactory.iphoneProduct();
        iphoneProduct.callup();
        iphoneProduct.sendSMS();

        iRouterProduct = huaweiFactory.irouterProduct();
        iRouterProduct.openWifi();
    }
}


(3) 抽象工厂模式优缺点:

优点

  • 具体产品在应用层的代码隔离,无需关心创建的细节

  • 将一个系列的产品统一到一起创建

缺点:

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难

  • 增加了系统的抽象性和理解难度


5、工厂模式小结:

  • 简单工厂模式:虽然某种程度上不符合设计原则,但实际使用最多

  • 工厂方法模式:不修改已有类的前提下,通过增加新的工厂类实现扩展

  • 抽象工厂模式:不可以增加产品,可以增加产品族


6、工厂模式的应用场景:

  • jdk中calendar的getInstance方法----简单工厂模式

  • JDBC中的Connection对象的获取

  • Spring中的IOC容器创建管理bean对象

  • 反射中Class对象的newInstance方法




二、建造者模式

它提供了一种创建对象的最佳方式


1、定义:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。


2、主要作用:

在用户不知道 对象的建造过程和细节的情况下就可以直接创建复杂的对象。

用户只需要给出指定复杂对象的类型和内容,建造者牧师负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)


3、四种角色[★ 结合第四点的建造房子理解]

1) Product(产品角色):一个具体的产品对象。

2) Builder(抽象建造者): 创建一个Product对象的各个部件指定的 接口/抽象类

3) ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。

4) Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。

它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。


4、举例:建造房子

需要建房子:这一过程为打桩、砌墙、封顶。不管是普通房子也好,别墅也好都 需要经历这些过程,下面我们使用建造者模式(Builder Pattern)来完成.

1、产品角色:Product-房子,定义了房子的属性

2、抽象建造者:Builder-抽象的工人,定义了一些建造房子组件的方法和接口

3、具体建造者:ConcreteBuilder-具体的工人,实现了建造房子组件

4、指挥者:Director-房子的指挥设计者,:核心负责指挥构建一个工程,决定了工程如何构建,按照什么顺序构建

// 产品:房子[定义了房子的属性]
public class Product {

    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;

    public String getBuildA() {
        return buildA;
    }

    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }

    public String getBuildB() {
        return buildB;
    }

    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }

    public String getBuildC() {
        return buildC;
    }

    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }

    public String getBuildD() {
        return buildD;
    }

    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }
}


// 抽象的建造者[抽象的工人]:只是定义一些方法和接口
public abstract class Builder {
    abstract void buildA(); // 地基
    abstract void buildB(); // 钢筋工程
    abstract void buildC(); // 铺电线
    abstract void buildD(); // 粉刷

    // 完工:得到产品
    abstract Product getProduct();
}



// 具体的建造者[工人]:
public class Worker extends Builder {

    private Product product;

    public Worker() {
         product = new Product();// 工人负责创建产品
    }

    @Override
    void buildA() {
        product.setBuildA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setBuildB("钢筋工程");
        System.out.println("钢筋工程");
    }

    @Override
    void buildC() {
        product.setBuildC("铺电线");
        System.out.println("铺电线");
    }

    @Override
    void buildD() {
        product.setBuildD("粉刷");
        System.out.println("粉刷");
    }

    @Override
    Product getProduct() {
        return product;
    }
}


// 指挥者:核心负责指挥构建一个工程,工程如何构建,按照什么顺序构建,由他决定
public class Director {

    // 指挥工人按照顺序建房子
    public Product build(Builder builder){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();
        return builder.getProduct();
    }
}



public class Test {
    public static void main(String[] args) {
        // 指挥
        Director director = new Director();
        // 指挥 具体的工人 完成产品
        Product build = director.build(new Worker());
        System.out.println(build.toString());
    }
}


5、建造者模式在JDK的应用和源码分析 (java.lang.StringBuilder中的建造者模式)

■ 源码中建造者模式角色分析

Appendable接口是抽象建造者, 定义了抽象方法,定义了多个append方法(抽象方法)

AbstractStringBuilder抽象类,实现了 Appendable接口方法AbstractStringBuilder 是建造者,只是不能实例化

StringBuilder 继承了AbstractStringBuilder,即充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由 AbstractStringBuilder 完成, 而StringBuilder 继承了 AbstractStringBuilder


6、建造者模式的优缺点

优点:

  • 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节
  • 用户使用不同的具体建造者即可得到不同的产品对象
  • 将复杂产品的创建步骤分解在不同的方法中,是得创建过程更加清晰
  • 具体的建造者之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库代码,符合“开闭原则”

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变的很庞大


7、抽象工厂模式VS建造者模式

抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品 由什么工厂生产即可

建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。



参考内容来源:《尚硅谷Java设计模式(图解+框架源码剖析)》 https://www.bilibili.com/video/BV1G4411c7N4
《【狂神说Java】通俗易懂的23种设计模式教学(停更)》https://www.bilibili.com/video/BV1mc411h719?p=5



如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

你可能感兴趣的:(设计模式之---工厂模式、建造者模式)