设计模式 | 工厂模式 & 抽象工厂

工厂模式的一个很大的特点是:创建具体的产品对象只需从工厂类中获得,而无需手动通过 new 来创建对象,即降低了客户端与产品之间的耦合。以下将通过实际例子来讲解简单工厂、工厂方法以及抽象工厂设计模式。

1. 简单工厂

模拟简单地从工厂获得产品的例子

(1)定义一个抽象产品 Car:

/**
 * 产品类:汽车
 */
public interface Car {
    void name();
}

(2)定义具体的 Car 产品:

/**
 * 具体要生产的产品:各种品牌的汽车
 */
public class Audi implements Car {
    @Override
    public void name() {
        System.out.println("奥迪~");
    }
}
/**
 * 具体要生产的产品:各种品牌的汽车
 */
public class Tesila implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉~");
    }
}

(3)定义生产汽车产品的工厂,其中提供一个静态方法以返回具体的汽车产品

/**
 * 生产汽车产品的工厂:根据汽车类型生产对应品牌的汽车
 */
public class CarFactory {
    public static Car getCar(String type) {
        if ("奥迪".equals(type)) {
            return new Audi();
        }
        if ("特斯拉".equals(type)) {
            return new Tesila();
        }
        return null;
    }
}

(4)客户端:消费者从工厂中获得汽车,而不需要手动创建 Car 对象:

/**
 * 客户端:获得汽车无需手动 new 对象,通过工厂获得即可
 */
public class Consumer {
    public static void main(String[] args) {
        Car car1 = CarFactory.getCar("奥迪");
        Car car2 = CarFactory.getCar("特斯拉");
        car1.name();
        car2.name();
    }
}

由于简单工厂相对简单,实际中用的相对较多。

对于简单工厂,如果要新增一种类型的汽车。那么我们就要在 CarFactory 中新增一个 if 分支去创建新类型的 Car,即需要修改工厂的代码。这违反了开闭原则(对修改关闭,对扩展开发),这也是简单工厂模式的主要弊端。如果要改进这点,可引入下面所说的工厂方法模式


2. 工厂方法

在简单工厂例子的基础上进行改进

(1)在简单工厂的基础上 ,抽象出 CarFactory 接口:

/**
 * 汽车工厂可以有不同实现,每种实现对应生产一种品牌的汽车
 */
public interface CarFactory {
    Car getCar();
}

(2)对于每种类型的 Car,都要定义一个与之对应的工厂:

/**
 * 生产奥迪品牌汽车的工厂
 */
public class AudiFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Audi();
    }
}
/**
 * 生产特斯拉品牌汽车的工厂
 */
public class TesilaFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Tesila();
    }
}

(3)此时,客户端(消费者)可以直接通过对应工厂的 getCar() 方法获得该品牌的 Car:

/**
 * 客户端:获得汽车无需手动 new 对象,通过工厂获得即可
 */
public class Consumer {
    public static void main(String[] args) {
        // 先创建具体工厂对象,然后再获得汽车
        Car car1 = new AudiFactory().getCar();
        Car car2 = new TesilaFactory().getCar();
        car1.name();
        car2.name();
    }
}

对于工厂方法,如果我们要新增一种类型的 Car,只需要额外新增一个对应的 Factory。这样做就无需改动原有代码,而是属于一种拓展的行为,符合开闭原则。但其缺点也比较明显:就是类比较多(将工厂抽象为接口),代码相对简单工厂较多。


3. 抽象工厂

抽象工厂适用于得到一个产品族的对象,而每个产品对象又有不同的产品等级结构。什么是产品族和产品等级结构呢?比如说,小米工厂可以生产小米手机和路由器,它们属于不同的产品,但是都属于同一个品牌,可理解为是同一个产品族(即小米系产品)。结合前面的工厂模式,产品接口的实现类则对应不同的产品等级结构,比如手机产品可以是小米手机、也可以是华为手机。

模拟多个供应商生产一系列产品的例子

(1)定义同一产品族的不同产品:手机 Phone、路由器 Router:

/**
 * 抽象工厂要生产的产品,手机 + 路由器构成一个产品族的对象
 */
public interface Phone {
    void name();
}
/**
 * 抽象工厂要生产的产品,手机 + 路由器构成一个产品族的对象
 */
public interface Router {
    void name();
}

(2)小米产品族的手机、路由器的具体实现:

/**
 * 小米产品族的手机
 */
public class XiaoMiPhone implements Phone {
    @Override
    public void name() {
        System.out.println("小米手机~");
    }
}
/**
 * 小米产品族的路由器
 */
public class XiaoMiRouter implements Router {
    @Override
    public void name() {
        System.out.println("小米路由器~");
    }
}

(3)华为产品族的手机、路由器的具体实现:

/**
 * 华为产品族的手机
 */
public class HuaWeiPhone implements Phone {
    @Override
    public void name() {
        System.out.println("华为手机~");
    }
}
/**
 * 华为产品族的路由器
 */
public class HuaWeiRouter implements Router {
    @Override
    public void name() {
        System.out.println("华为路由器~");
    }
}

(4)定义抽象工厂,提供获取同一产品族的不同产品的接口:

/**
 * 抽象工厂,目的是为了生产同一产品族的不同产品,如小米产品族的手机和路由器
 */
public interface ProductFactory {
    Phone createPhone();
    Router createRouter();
}

(5)工厂的具体实现类,小米工厂生产小米产品族的产品、华为工厂生产华为产品族的产品:

/**
 * 生产小米系列产品的具体工厂
 */
public class XiaoMiFactory implements ProductFactory {
    @Override
    public Phone createPhone() {
        return new XiaoMiPhone();
    }

    @Override
    public Router createRouter() {
        return new XiaoMiRouter();
    }
}
/**
 * 生产华为系列产品的具体工厂
 */
public class HuaWeiFactory implements ProductFactory {
    @Override
    public Phone createPhone() {
        return new HuaWeiPhone();
    }

    @Override
    public Router createRouter() {
        return new HuaWeiRouter();
    }
}

(6)客户端:通过具体的工厂对象可得到同一产品族的不同产品,如通过小米工厂可得到小米手机以及小米路由器。

/**
 * 客户端:类似于工厂方法,先创建对应工厂对象,然后获得产品;
 *         只不过抽象工厂可以得到不同的产品(同一产品族)
 */
public class Consumer {
    public static void main(String[] args) {
        /** 生产小米工厂的产品 */
        ProductFactory factory1 = new XiaoMiFactory();
        Phone phone1 = factory1.createPhone();
        Router router1 = factory1.createRouter();
        phone1.name();
        router1.name();
        /** 生产华为工厂的产品 */
        ProductFactory factory2 = new HuaWeiFactory();
        Phone phone2 = factory2.createPhone();
        Router router2 = factory2.createRouter();
        phone2.name();
        router2.name();
    }
}

从系统的结构来看,抽象工厂与工厂方法还是有些相似之处的。工厂方法也抽象出了工厂接口,但是它只生产一种产品,而抽象工厂可以生产多种不同的产品(同一产品族)。这也使得抽象工厂的类相对较多。

对于抽象工厂,如果要新增一种产品的话,那么每个工厂实现类的代码都要进行改动,这是十分麻烦的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值