Java 进阶JVM · Java虚拟机原理 · JVM上语言·框架· 生态系统java学习快到碗里来

设计模式(二)工厂方法模式

2020-12-29  本文已影响0人  我犟不过你

1、概述

工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。

2、适用场景

1)不确定对象的类别、个数或者依赖关系。
2)需要扩展工具库或者内部组件。
3)需要重复使用的对象(例如资源池等)。

3、实例

有以下业务场景:一个商店,出售多种货物,包括汽车car,船ship,飞机plane。

3.1 不使用工厂模式

定义三个实体类:

import lombok.Data;

/**
 * Car
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Car {

    private String name;

    private String price;

    public void run() {
        System.out.println("the car is running");
    }
}
import lombok.Data;

/**
 * Plane
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Plane {

    private String name;

    private String price;

    public void run() {
        System.out.println("the Plane is running");
    }
}
import lombok.Data;

/**
 * Ship
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Ship {

    private String name;

    private String price;

    public void run() {
        System.out.println("the Ship is running");
    }
}

定义接口和实现:

接口实现方式

如上图所示:一个接口IShop,有一个实现类ShopImpl,获取三种产品的方法在这个接口中定义了三次。

/**
 * IShop
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
public interface IShop {

    /**
     * 获取汽车
     * @date: 2020/12/29
     * @param
     * @return com.cloud.bssp.designpatterns.factorymethod.withoutdesign.factory.Car
     * @author weirx
     * @version 3.0
     */
    Car getCar();

    /**
     * 获取船
     * @date: 2020/12/29
     * @param
     * @return com.cloud.bssp.designpatterns.factorymethod.withoutdesign.factory.Car
     * @author weirx
     * @version 3.0
     */
    Ship getShip();

    /**
     * 获取飞机
     * @date: 2020/12/29
     * @param
     * @return com.cloud.bssp.designpatterns.factorymethod.withoutdesign.factory.Car
     * @author weirx
     * @version 3.0
     */
    Plane getPlane();
}
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Car;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.IShop;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Plane;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Ship;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * ShopImpl
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Slf4j
@Service
public class ShopImpl implements IShop {
    @Override
    public Car getCar() {
        log.info("this is car");
        return new Car();
    }

    @Override
    public Ship getShip() {
        log.info("this is Ship");
        return new Ship();
    }

    @Override
    public Plane getPlane() {
        log.info("this is Plane");
        return new Plane();
    }
}

创建一个测试类:

import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Car;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.IShop;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Plane;
import com.cloud.bssp.designpatterns.factorymethod.withoutdesign.Ship;
import com.cloud.bssp.BsspUserApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * test
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BsspUserApplication.class)
public class TestDemo {

    @Autowired
    private IShop shop;

    @Test
    public void testWithout() {

        Car car = shop.getCar();
        car.run();

        Ship ship = shop.getShip();
        ship.run();

        Plane plane = shop.getPlane();
        plane.run();

    }

}

执行结果:

2020-12-29 14:54:24.078  INFO 16884 --- [           main] c.c.b.d.f.withoutdesign.impl.ShopImpl    : this is car
the car is running
2020-12-29 14:54:24.078  INFO 16884 --- [           main] c.c.b.d.f.withoutdesign.impl.ShopImpl    : this is Ship
the Ship is running
2020-12-29 14:54:24.078  INFO 16884 --- [           main] c.c.b.d.f.withoutdesign.impl.ShopImpl    : this is Plane
the Plane is running

3.2 使用工厂模式

创建一个Product接口,定义run()方法:

/**
 * Product
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
public interface Product {

    /**
     * 行驶
     * @date: 2020/12/29
     * @param
     * @return void
     * @author weirx
     * @version 3.0
     */
    void run();
}

定义三个实体类:

import lombok.Data;

/**
 * Car
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Car implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the car is running");
    }
}
import lombok.Data;

/**
 * Plane
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Plane implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Plane is running");
    }
}
import lombok.Data;

/**
 * Ship
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Ship implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Ship is running");
    }
}

接口与实现如下图所示:

工厂方法

一个接口返回Product,三个实现分别返回三个产品实体。

定义一个工厂方法接口:

/**
 * IShop
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
public interface IShop {

    /**
     * 获取商品
     * @date: 2020/12/29
     * @param
     * @return java.lang.Object
     * @author weirx
     * @version 3.0
     */
    Product getProduct();
}

定义工厂接口实现:

/**
 * Ship
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Ship implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Ship is running");
    }
}
/**
 * Plane
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Plane implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Plane is running");
    }
}
import lombok.Data;

/**
 * Car
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@Data
public class Car implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the car is running");
    }
}

定义一个测试类:

import com.cloud.bssp.BsspUserApplication;
import com.cloud.bssp.designpatterns.factorymethod.usedesign.IShop;
import com.cloud.bssp.designpatterns.factorymethod.usedesign.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * test
 * @date: 2020/12/29
 * @author weirx
 * @version 3.0
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BsspUserApplication.class)
public class TestDemo {

    @Autowired
    private IShop shipImpl;

    @Autowired
    private IShop carImpl;

    @Autowired
    private IShop planeImpl;

    @Test
    public void testUsed() {
        //以下使用注入的方式,注意在工厂IShop的每个实现指定bean的名称
        Product car = carImpl.getProduct();

        Product ship = shipImpl.getProduct();

        Product plane = planeImpl.getProduct();

        //以下使用new的方式
//        IShop planeImpl = new PlaneImpl();
//        Product plane = planeImpl.getProduct();
//
//
//        IShop carImpl = new CarImpl();
//        Product car = carImpl.getProduct();
//        car.run();
//
//        IShop shipImpl = new ShipImpl();
//        Product ship = shipImpl.getProduct();

        car.run();
        plane.run();
        ship.run();

    }

}

运行结果:

2020-12-29 15:01:59.394  INFO 21132 --- [           main] c.c.b.d.f.usedesign.impl.CarImpl         : this is car
2020-12-29 15:01:59.394  INFO 21132 --- [           main] c.c.b.d.f.usedesign.impl.ShipImpl        : this is Ship
2020-12-29 15:01:59.394  INFO 21132 --- [           main] c.c.b.d.f.usedesign.impl.PlaneImpl       : this is plane
the car is running
the Plane is running
the Ship is running

4、分析

分析对比以上两种实现方式:

实体类:

使用工厂发的实体类,定义了一个接口,其内部可以定义一些通用的方法,实体类可以通过实现该接口重写该方法,方法名统一。

在没使用工厂的实体类中,虽然也可以自定义方法,但是没有对方法的名称有限制,可自定义。后续实体越来越多,可能通用的方法名会起的多种多样,造成代码混乱,不利于统一。

接口

实用工厂方式,提供一个统一接口,内部提供一个统一获取产品的方法,其具体返回那种产品由其实现方法进行指定。此接口永远不会被修改,只会在其实现类去扩展。

未使用的工厂方法的同样提供一个接口,但是其内部分别提供了获取三种产品的三个方法,后面随着产品越来越多,这个接口的方法也会越来越多。

实现类

使用工厂方法的针对不同的产品分别实现了各个产品的实现类,每个实现类返回对应的产品,相互之间没有任何耦合。

未使用工厂方法的在一个实现类内有三种产品的获取方法,随着产品种类增加,此类会越来越长,容易造成代码耦合和过长,不利于代码阅读和管理,扩展性很差,每次新增都需要修改这个实现类。

5、总结

最后总结下上面例子中使用工厂方法的优缺点:

优点:
1)符合开闭原则,对扩展开放,对修改关闭。
2)符合迪米特原则,类与类之间没有关联,降低耦合。
3)符合单一职责,一个类或方法只负责一件事。

缺点:
引入了很多的子类,代码变得复杂。

上一篇 下一篇

猜你喜欢

热点阅读