抽象工厂模式与建造者模式——用一个实例来解释

最近在学习设计模式,在创建型模式中比较难理解的主要是工厂模式与建造者模式,二者有许多相似之处,但是本质上还是不同的。

目录

1 实例

 1.1 工厂类的代码(抽象工厂模式)

1.2 实体类(建造者模式)

1.3 结果

2. 优点

2.1 抽象工厂类的优点

2.2 建造者模式的优点

3.总结

1.抽象工厂模式:是工厂模式的一种。工厂模式又分为工厂方法模式与抽象工厂模式。工厂方法模式在本文中不进行详细叙述,简单来说就是给一个工厂负责创建一个类。而抽象工厂模式负责创建一个产品族,例如本文要举的例子中,男士帽子、男士大衣、男士裤子属于一个产品族;女士帽子、女士大衣、女士裤子属于另一个产品族。如果只用工厂方法模式,那就需要创建6个工厂类。而用抽象工厂模式只需要2个工厂类,分别是MaleClothesFactory和FemaleClothesFactory,这两个工厂类又同时实现了AbsFactory接口(在后面的例子中会用到)

2.建造者模式:将部件和其组装过程分开,一步一步创建一个复杂的对象。相比于工厂模式创建一类对象,建造者模式更注重于该对象的属性,例如创造男士大衣时需要多少个口袋、衣服的材料如何等等。

1 实例

介绍完了概念,下面引入一个实例同时可以用到抽象工厂模式和建造者模式。

现在有一个工厂,可以同时生产男士帽子、男士大衣、男士裤子、女士帽子、女士大衣、女士裤子共6种产品。要是按照工厂方法模式,需要定义男士帽子工厂类、男士大衣工厂类、男士裤子工厂类、女士帽子工厂类、女士大衣工厂类、女士裤子工厂类以及各自的实体类,容易发生类爆炸。其中男士帽子、女士帽子是同一产品等级,都是帽子;男士大衣、女士大衣是同一产品等级,都是大衣;男士裤子、女士裤子是同一产品等级,都是裤子。男士帽子、男士大衣、男士裤子是同一产品族,都是男士衣服;女士帽子、女士大衣、女士裤子是同一产品族,都是女士衣服。所以这个案例可以使用抽象工厂模式实现。类图如下:

 IDEA中目录如下:

 1.1 工厂类的代码(抽象工厂模式)

抽象工厂:

public interface AbsFactory {
    // 创建帽子
    Hat createHat();
    // 创建大衣
    Coat createCoat();
    // 创建裤子
    Pant createPant();
}

具体工厂——男士衣服工厂

public class MaleClothesFactory implements AbsFactory {
    @Override
    public Hat createHat() {
        return new MaleHat.Builder().build();
    }

    @Override
    public Coat createCoat() {
        return new MaleCoat.Builder().build();
    }

    @Override
    public Pant createPant() {
        return new MalePant.Builder().build();
    }
}

 具体工厂——女士衣服工厂

public class FemaleClothesFactory implements AbsFactory {
    @Override
    public Hat createHat() {
        return new FemaleHat.Builder().build();
    }

    @Override
    public Coat createCoat() {
        return new FemaleCoat.Builder().build();
    }

    @Override
    public Pant createPant() {
        return new FemalePant.Builder().build();
    }
}

可以看出工厂生成的实体类都是通过Builder来创建的,这是因为对于每一个实体类都是用建造者模式来创建的。 

1.2 实体类(建造者模式)

我们以大衣为例,抽象类大衣下有两个子类:男士大衣类与女士大衣类。采用“链式调用”,在抽象大衣类中创建一个抽象Builder类,权限修饰符为protected,可以被子类访问。

抽象大衣类代码如下:

public abstract class Coat {
    //Coat的必需属性 采用protected权限修饰符可以让子类访问
    protected String pocket;
    protected String material;

    protected Coat(Builder builder) {
        this.pocket = builder.pocket;
        this.material = builder.material;
    }

    // 抽象方法由子类实现
    public abstract void wearCoat();

    // 抽象的Builder类 具体方法由子类实现 采用了链式调用
    protected abstract static class Builder {
        protected String pocket;
        protected String material;

        public abstract Builder pocket(String val);
        public abstract Builder material(String val);
        public abstract Coat build();
    }
}

男士大衣类是继承了抽象大衣类的子类(女士大衣类同,所以只展示男士大衣类的代码)。男士大衣类中的内部类Builder继承了抽象大衣类中的内部类Builder。注:重写方法的返回值类型范围要小于等于原方法的返回值类型,例如抽象类Builder的build()方法返回值类型是Coat,但实现类Builder的build()方法返回值类型是MaleCoat:

public class MaleCoat extends Coat {

    private MaleCoat(Builder builder) {
        super(builder);
    }

    
    @Override
    public void wearCoat() {
        System.out.println("穿上男士大衣");
    }

    // 继承了抽象大衣类的内部类Builder
    public static final class Builder extends Coat.Builder{
        @Override
        public Builder pocket(String val) {
            pocket = val;
            return this;
        }

        @Override
        public Builder material(String val) {
            material = val;
            return this;
        }

        @Override
        public MaleCoat build() {
            return new MaleCoat(this);
        }
    }


    @Override
    public String toString() {
        return "MaleCoat{" +
                "pocket='" + pocket + '\'' +
                ", material='" + material + '\'' +
                '}';
    }
}

其余帽子类产品和裤子类产品的构建都同大衣类。

1.3 结果

创建一个客户端Client,以男士衣服产品族为例子,创建男士大衣,男士帽子、男士裤子

public class Client {
    public static void main(String[] args) {
        AbsFactory factory = new MaleClothesFactory();
        Hat hat = factory.createHat();
        System.out.println(hat);
        hat.wearHat();

        Coat coat = factory.createCoat();
        System.out.println(coat);
        coat.wearCoat();

        Pant pant = factory.createPant();
        System.out.println(pant);
        pant.wearPant();
    }
}

最终结果如下:

MaleHat{shape='鸭舌帽', material='布料'}
戴上男士帽子
MaleCoat{pocket='2个', material='全棉'}
穿上男士大衣
MalePant{pocket='2个', material='全棉'}
穿上男士裤子

2. 优点

采用抽象工厂模式和建造者模式最直接的优点就是代码解耦,提升了后续代码的维护与扩展。

2.1 抽象工厂类的优点

假如此时我们想要生产儿童大衣ChildCoat类,只需要新建一个ChildCoat类继承Coat抽象类。并且在ChildCoat类中创建内部类Buider继承Coat.Buider。

// 新增的需求
public class ChildCoat extends Coat{
    private ChildCoat(Builder builder) {
        super(builder);
    }

    @Override
    public void wearCoat() {
        System.out.println("穿上儿童大衣");
    }

    public static final class Builder extends Coat.Builder{

        @Override
        public Builder pocket(String val) {
            pocket = val;
            return this;
        }

        @Override
        public Builder material(String val) {
            material = val;
            return this;
        }

        @Override
        public ChildCoat build() {
            return new ChildCoat(this);
        }
    }
}

2.2 建造者模式的优点

女士大衣的必要属性有pocket和material,这两个属性是在抽象类Coat中就已经定义好的。当我们想给女士大衣类再加一个属性decoration,增加一点装饰。只需要在女士大衣类增加该属性,并且在内部类Builder中也增加该属性,并且增加public Builder decorate(String val)的方法:

public class FemaleCoat extends Coat {
    private String decoration; // 新增内容

    private FemaleCoat(Builder builder) {
        super(builder);
        this.decoration = builder.decoration; // 新增内容
    }

    @Override
    public String toString() {
        return "FemaleCoat{" +
                "decoration='" + decoration + '\'' +
                ", pocket='" + pocket + '\'' +
                ", material='" + material + '\'' +
                '}';
    }

    @Override
    public void wearCoat() {
        System.out.println("穿上女士大衣");
    }

    public static final class Builder extends Coat.Builder {
        private String decoration;// 新增内容

        public Builder decorate(String val) {// 新增内容
            this.decoration = val;
            return this;
        }

        @Override
        public Builder pocket(String val) {
            pocket = val;
            return this;
        }

        @Override
        public Builder material(String val) {
            material = val;
            return this;
        }

        public FemaleCoat build() {
            return new FemaleCoat(this);
        }
    }
}

最后在女士衣服的工厂类中链式调用增加decoration()方法即可,如下:

    @Override
    public Coat createCoat() {
        return new FemaleCoat.Builder()
                .pocket("2个")
                .material("全棉")
                .decorate("小花")
                .build();
    }

控制台输出如下:

FemaleCoat{decoration='小花', pocket='2个', material='全棉'}
穿上女士大衣

3.总结

一句话总结,抽象工厂模式注重于创建不同种类的对象,建造者模式着重于一个对象创建时的属性构成。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值