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

作者: 我犟不过你 | 来源:发表于2020-12-29 15:36 被阅读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)符合单一职责,一个类或方法只负责一件事。

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

相关文章

  • 设计模式四、抽象工厂模式

    系列传送门设计模式一、单例模式设计模式二、简单工厂模式设计模式三、工厂模式设计模式四、抽象工厂模式 抽象工厂模式 ...

  • 2021-11-16 - 学习记录

    设计模式学习:创建型:工厂(工厂方法,抽象工厂),建造者,单例,原型 设计模式:工厂模式 简单工厂 工厂方法 抽象工厂

  • 设计模式三、工厂模式

    系列传送门设计模式一、单例模式设计模式二、简单工厂模式设计模式三、工厂模式设计模式四、抽象工厂模式 工厂模式 在一...

  • 工厂模式

    工厂模式 就是工厂---生产-->产品 在设计模式中,分为 简单工厂模式, 工厂方法模式,抽象工厂模式. 工厂模式...

  • PHP-浅谈单例模式和工厂模式

    PHP中常用的设计模式有单例模式、工厂模式(简单工厂模式、工厂方法模式和抽象工厂方法模式)、适配模式、策略模式。 ...

  • 设计模式-工厂模式

    设计模式1 设计模式2 工厂模式 工厂模式可简单的分为三类:简单工厂,工厂方法,抽象工厂 简单工厂模式 定义 简单...

  • 设计模式之工厂方法模式(创建型)

    一、模式定义 工厂方法模式:又称工厂模式,也叫虚拟构造器模式,属于构建型设计模式,工厂方法模式是在简单工厂模式上进...

  • spring 设计模式篇(前)

    设计模式俗称:套路 一、spring常见设计模式 (23种设计模式) 创建型:工厂方法模式、抽象工厂模式、建造者...

  • 设计模式一、单例模式

    系列传送门设计模式一、单例模式设计模式二、简单工厂模式设计模式三、工厂模式设计模式四、抽象工厂模式 简单单例(推荐...

  • 设计模式系列-简单工厂模式

    JAVA设计模式系列: 单例模式 观察者模式 模板方法模式 简单工厂模式 定义 简单工厂模式又叫做静态工厂方法模式...

网友评论

    本文标题:设计模式(二)工厂方法模式

    本文链接:https://www.haomeiwen.com/subject/xkmfoktx.html