设计模式之抽象工厂模式


设计模式是经验总结,是学习软件设计的有效方法,因此,了解和理解现有的设计模式,是提高软件设计的有效途径之一,这里将介绍相关的设计模式,并通过示例了理解其用法。

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。
定义
抽象工厂模式属于创建型模式,它提供了一种创建对象的最佳方式。
意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决: 主要解决接口选择的问题。
何时使用: 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决: 在一个产品族里面,定义多个产品。
关键代码: 在一个工厂里聚合多个同类产品。
应用实例: 工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。
优点: 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点: 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
注意事项: 产品族难扩展,产品等级易扩展。

示例

这里以产品的生产和包装为例,来说明如何使用抽象工厂模式。
现在要配套生产两个系列的螺钉和螺母,分别是M6和M10,完成生产后进行装箱,以便于运输,这是基本的设计思路,下面来看看具体实现。
和工厂方法模式类似,要生产M6和M10的螺钉和螺母,想要进行抽象,通过接口的实现来表明对应的产品,先来看看螺钉的接口,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

//螺钉
public interface IScrew {
    public void print();
}

有了螺钉的接口,就可以实现M6螺钉了,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class ScrewM6 implements IScrew {
    @Override
    public void print() {
        System.out.println("6mm螺纹螺钉");
    }
}

M10的螺钉的代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class ScrewM10 implements IScrew {
    @Override
    public void print() {
        System.out.println("10mm螺纹螺钉");
    }
}

类似地,可以产生对应的螺母类,螺母接口代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public interface INut {
    public void print();
}

M6的螺母的代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class NutM6 implements INut {
    @Override
    public void print() {
        System.out.println("6mm螺纹螺母");
    }
}

M10的螺母的代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class NutM10 implements INut {
    @Override
    public void print() {
        System.out.println("10mm螺纹螺母");
    }
}

有了这些产品,就可以通过工厂来生产这些产品了,同样地,定义一个工厂接口,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public interface IAbstractFactory {
    public IScrew makeScrew();

    public INut makeNut();
}

工厂中提供生产产品的方法,即工厂方法,为了完成有针对性的生产,就需要产生M6和M10的螺钉和螺纹的生产工厂,即M6的工厂生产M6的螺钉和螺纹,M10的工厂生产M10的螺钉和螺纹,那么,M6的工厂代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class ConcreteFactoryM6 implements IAbstractFactory {
    @Override
    public IScrew makeScrew() {
        return new ScrewM6();
    }

    @Override
    public INut makeNut() {
        return new NutM6();
    }
}

M10的工厂代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class ConcreteFactoryM10 implements IAbstractFactory {
    @Override
    public IScrew makeScrew() {
        return new ScrewM10();
    }

    @Override
    public INut makeNut() {
        return new NutM10();
    }
}

有了工厂,能够生产出系列产品,还需要对产品进行装箱,即将产品放入包装箱中,显示包装箱的清单,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class PackingCase {
    private int amount;
    private int numberOfScrew = 0;
    private int numberOfNut = 0;
    private IScrew[] screws;
    private INut[] nuts;

    public PackingCase(int amount) {
        this.amount = amount;
        screws = new IScrew[amount];
        nuts = new INut[amount];
    }

    int amount() {
        return amount;
    }

    public void putTheScrewsIn(IScrew screw) {
        if (numberOfScrew == amount) {
            return;
        } else {
            numberOfScrew++;
            screws[numberOfScrew - 1] = screw;
        }
    }

    public void putTheNutIn(INut nut) {
        if (numberOfNut == amount) {
            return;
        } else {
            numberOfNut++;
            nuts[numberOfNut - 1] = nut;
        }
    }

    public void showDetail() {
        int i;
        for (i = 0; i < numberOfScrew; i++) {
            screws[i].print();
        }
        for (i = 0; i < numberOfNut; i++) {
            nuts[i].print();
        }
    }
}

现在,可以进行产品生产和装箱,那么,需要这样的动作能够集成到一起,自动完成生产和装箱过程,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

public class ProductionMachine {
    private IAbstractFactory factory = null;

    public void setFactory(IAbstractFactory factory) {
        this.factory = factory;
    }

    public void packing(PackingCase packingCase) {
        int i;
        for (i = 0; i <= packingCase.amount(); i++) {
            packingCase.putTheScrewsIn(factory.makeScrew());
            packingCase.putTheNutIn(factory.makeNut());
        }
    }
}

这样,就可以进行产品的生产和装箱了,在使用时,直接指定装箱规格即可,代码如下:

package cn.lut.curiezhang.designpattern.abstractfactory;

/**
 * Client
 *
 */
public class Client
{
    static ProductionMachine machine = new ProductionMachine();
    static PackingCase packingCase1 = new PackingCase(5);
    static PackingCase packingCase2 = new PackingCase(3);

    public static void main( String[] args )
    {
        machine.setFactory(new ConcreteFactoryM6());
        machine.packing(packingCase1);
        packingCase1.showDetail();

        System.out.println();

        machine.setFactory(new ConcreteFactoryM10());
        machine.packing(packingCase2);
        packingCase2.showDetail();
    }
}

代码执行结果如下图所示:
result
代码实现就是这样的,下面来看看上面设计模式的基本结构,通过类图了解其基本构成,如下图所示:
类图
了解了其基本结构,就需要搞清楚这些类是怎么样来完成交互的,也就是这些对象之间是如何协作的?就通过顺序图来了解其工作过程,如下图所示:
顺序图
请注意其交互过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值