工厂模式

SimpleFactory

说到工厂,我们应该能想到,造汽车的有汽车工厂,造轮船的有轮船工厂,映射到Java中,造对象的就应该有对象工厂,比如说我想要买一辆车,那我只需要去汽车工厂(先不去4S店)里面告诉它什么品牌的汽车,具体参数,给钱提车就完了,我并不需要了解汽车是如何造出来的,也就是屏蔽了造车的细节,这样的好处就是对于买家来说,简单方便,用户体验大大提升,对于卖家来说我厂生产汽车的具体细节不会外露。

需求:

用户提出要圆形、三角形、菱形等等。

解决方案1:

public void m1() {
    // 用户需要圆,自己new一个
    Circle circle = new Circle();
    // 用户需要三角形,自己new一个
    Triangle triangle = new Triangle();
}

解决方案2:

可以使用简单工厂的模式,只需要将工厂暴露给调用方,调用方给出自己想要的形状就可以了,因为所有的设计模式都是面向接口编程,所以接口是少不了的。

定义一个Shape接口

/**
 * Description: 所有图形都有的公共属性,定义成抽象类也可以,接口也可
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/7
 * @Since v1.0
 */
public interface Shape {

    void draw();

}

Shape接口的实现类CricleShape

/**
 * Description: 圆形实例
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/7
 * @Since v1.0
 */
public class CircleShape implements Shape {

    public CircleShape() {
        System.out.println("圆形创建出来。");
    }

    @Override
    public void draw() {
        System.out.println("画出一个圆形。");
    }

}

Shape接口的实现类Triangle

/**
 * Description: 三角形实例
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/7
 * @Since v1.0
 */
public class TriangleShape implements Shape {

    public TriangleShape() {
        System.out.println("三角形创建出来。");
    }

    @Override
    public void draw() {
        System.out.println("画出一个三角形");
    }

}

简单工厂类,对外暴露方法

/**
 * Description: 简单工厂类
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/7
 * @Since v1.0
 */
public class ShapeFactory {

    /**
     * 1. 简单工厂模式对外屏蔽了对象的创建细节,需要什么对象直接从工厂获取。
     * 2. 将获取对象的方法声明成静态的,由工厂类,向外提供服务。
     */
    public static Shape getShape(String shapeName) {
        Shape shape = null;
        if (null != shapeName && !"".equals(shapeName)) {
            if ("circle".equalsIgnoreCase(shapeName)) {
                shape = new CircleShape();
            } else if ("triangle".equalsIgnoreCase(shapeName)) {
                shape = new TriangleShape();
            }
        }
        return shape;
    }

}

测试类

在调用方只需要给工厂提供想要的形状即可,不必关心形状是如何来的。

/**
 * Description: 简单工厂模式测试用例
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/7
 * @Since v1.0
 */
public class Test01 {

    @Test
    public void m1() {
        Shape circle = ShapeFactory.getShape("circle");
        circle.draw();
    }

}

简单工厂,根本来说不属于23中设计模式中的一种,但工厂方法模式和抽象工厂模式都是由它演变来的,它的缺点:系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,违背了OCP原则。

FactoryMethod

还是上面的汽车例子,简单工厂类中维护了创建不同汽车的逻辑,比如说包括宝马,奔驰,奥迪,但后续需求越来越多,又增添了长城,马自达,大众等等品牌,那么这个工厂类的创建逻辑会越来越多,现实中,宝马有宝马自己的工厂,奔驰也有奔驰自己的工厂,映射到Java中,不同的类,应该有各自的工厂,这样的目的就是为了维护扩展方便,同时遵循了OCP原则。

设计模式是基于接口的,首先要有一个汽车的接口Car,它用来规定汽车的公共功能:

/**
 * Description: 所有汽车的公共接口
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface Car {

    /**
     * car在跑。
     */
    void running();

}

然后是具体品牌汽车的实例:

宝马:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BaoMa implements Car {

    @Override
    public void running() {
        System.out.println("宝马飞驰。");
    }

}

奔驰:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BenChi implements Car {

    @Override
    public void running() {
        System.out.println("奔驰奔跑。");
    }

}

然后是各自品牌的工厂,在创建各自工厂之前,最好加一层汽车工厂接口,目的是用多态来返回不同的工厂,使代码更加灵活。

汽车工厂接口:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface CarFactory {

    Car createCar();

}

各自的汽车工厂类:

宝马工厂:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BaoMaFactory implements CarFactory {

    @Override
    public Car createCar() {
        System.out.println("宝马工厂生产汽车。");
        return new BaoMa();
    }

}

奔驰工厂:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BenChiFactory implements CarFactory {

    @Override
    public Car createCar() {
        System.out.println("奔驰工厂生产汽车。");
        return new BenChi();
    }

}

测试类:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class Test01 {

    @Test
    public void m1() {
        // 1. 先获取宝马车的工厂,如果想改奔驰的,仅改动一行代码即可。
        CarFactory carFactory = new BaoMaFactory();
        // 2. 利用工厂来制造汽车
        Car car = carFactory.createCar();
        car.running();
    }

}

工厂方法模式就很利于扩展,且不需要改动原来的代码,不管增加多少个品牌,只需要增加对应的工厂,以及实例就好了。

适用场景:

  1. 客户端不需要知道它所创建的对象的类。例子中我们不知道每个汽车具体叫什么名,只知道创建它的工厂名就完成了创建过程。
  2. 客户端可以通过子类来指定创建对应的对象。

AbstractFactory

抽象工厂的局限性比较大,并且它不符合OCP原则,工厂方法模式是创建一个对象,而抽象工厂它可以创建一组对象,这是和工厂方法模式最大的不同点。上述汽车的例子,假如汽车生产出来,出厂之前,我还需要给汽车做一个包装保养的服务,比如宝马有宝马的包装保养,奔驰有奔驰的包装保养,那是不是应该再创建一个专门做保养的工厂呢,肯定不是,抽象工厂的作用就是将汽车的生产、保养,以及后续的任务都做到一起,秉承一条龙服务,包括汽车的生产,包装,保养,维修等。

首先定义基本接口:

  • 汽车公共接口Car:
/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface Car {

    /**
     * car在跑。
     */
    void running();
    
}
  • 汽车维修服务接口CarFix:
/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface CarFix {

    /**
     * 汽车维修服务
     */
    void carFix(Car car);

}
  • 汽车包装服务接口CarPack:
/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface CarPack {

    /**
     * 汽车包装服务
     */
    void carPack(Car car);

}

三个接口的实现类:

  • Car类

宝马BaoMa:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BaoMa implements Car {

    @Override
    public void running() {
        System.out.println("宝马飞驰。");
    }

}

奔驰BenChi:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BenChi implements Car {

    @Override
    public void running() {
        System.out.println("奔驰奔跑。");
    }

}
  • 维修类CarFixService:
/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class CarFixService implements CarFix {

    @Override
    public void carFix(Car car) {
        System.out.println(car.getClass() + "在维修。");
    }

}
  • 包装类CarPackService:
/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class CarPackService implements CarPack {

    @Override
    public void carPack(Car car) {
        System.out.println(car.getClass() + "精美包装。");
    }

}

抽象工厂:

抽象工厂中提供了此工厂所有的服务以及功能,包括汽车生产、包装、维修等。

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public interface AbstractFactory {

    /**
     * 汽车创造
     */
    Car createCar();

    /**
     * 汽车修理服务
     */
    CarFix carFix(Car car);

    /**
     * 汽车包装服务
     */
    CarPack carPack(Car car);

}

具体的汽车工厂:

奔驰工厂BenChiFactory:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BenChiFactory implements AbstractFactory {

    @Override
    public Car createCar() {
        return new BenChi();
    }

    @Override
    public CarFix carFix(Car car) {
        return new CarFixService();
    }

    @Override
    public CarPack carPack(Car car) {
        return new CarPackService();
    }
}

宝马工厂BaoMaFactory:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class BaoMaFactory implements AbstractFactory {

    @Override
    public Car createCar() {
        return new BaoMa();
    }

    @Override
    public CarFix carFix(Car car) {
        return new CarFixService();
    }

    @Override
    public CarPack carPack(Car car) {
        return new CarPackService();
    }

}

测试类:

/**
 * Description:
 * @From www.zhangjianbing.com
 * @Author 70KG
 * @Date 2019/3/11
 * @Since v1.0
 */
public class Test01 {

    @Test
    public void m1() {
        // 1. 先按名字获取工厂
        AbstractFactory factory = new BenChiFactory();
        // 2. 生产车
        Car car = factory.createCar();
        // 3. 包装车
        CarPack carPack = factory.carPack(car);
        carPack.carPack(car);
        // 4. 上路
        car.running();
        // 5. 修理车
        CarFix carFix = factory.carFix(car);
        carFix.carFix(car);
        // -- 以上全部都是由工厂来完成。
    }

}

测试结果:

生产奔驰。
BenChi精美包装。
奔驰奔跑。
BenChi在维修。

抽象工厂适用场景:

  1. 和工厂方法一样客户端不需要知道它所创建的对象的类。
  2. 需要一组对象共同完成某种功能时。并且可能存在多组对象完成不同功能的情况。
  3. 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)

你可能感兴趣的:(工厂模式)