前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式系列| 工厂方法模式

设计模式系列| 工厂方法模式

作者头像
用户7656790
发布2021-04-13 10:35:28
2200
发布2021-04-13 10:35:28
举报
文章被收录于专栏:五角钱的程序员

❝这是设计模式的第二篇,我们都知道「工厂模式」有三种,「简单工厂,工厂方法,抽象工厂」,这篇让我们来认识一下「工厂模式」


1、概述

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

2、适用场景

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

3、实例

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

3.1 不使用工厂模式

定义三个实体类

代码语言:javascript
复制
import lombok.Data;

/**
 * Car
 */
@Data
public class Car {

    private String name;

    private String price;

    public void run() {
        System.out.println("the car is running");
    }
}
代码语言:javascript
复制
import lombok.Data;

/**
 * Plane
 */
@Data
public class Plane {

    private String name;

    private String price;

    public void run() {
        System.out.println("the Plane is running");
    }
}
代码语言:javascript
复制
import lombok.Data;

/**
 * Ship
 */
@Data
public class Ship {

    private String name;

    private String price;

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

定义接口和实现

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

代码语言:javascript
复制
/**
 * IShop
 */
public interface IShop {

    /**
     * 获取汽车
     */
    Car getCar();

    /**
     * 获取船
     */
    Ship getShip();

    /**
     * 获取飞机
     */
    Plane getPlane();
}
代码语言:javascript
复制
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
 */
@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();
    }
}

创建一个测试类

代码语言:javascript
复制

/**
 * test
 */
@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();

    }
}

执行结果

代码语言:javascript
复制
2021-01-10 14:54:24.078  INFO 16884 --- [           main] c.c.b.d.f.withoutdesign.impl.ShopImpl    : this is car
the car is running
2021-01-10 14:54:24.078  INFO 16884 --- [           main] c.c.b.d.f.withoutdesign.impl.ShopImpl    : this is Ship
the Ship is running
2021-01-10 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()方法

代码语言:javascript
复制
/**
 * Product
 */
public interface Product {

    /**
     * 行驶
     */
    void run();
}

定义三个实体类

代码语言:javascript
复制
import lombok.Data;

/**
 * Car
 */
@Data
public class Car implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the car is running");
    }
}
代码语言:javascript
复制
import lombok.Data;

/**
 * Plane
 */
@Data
public class Plane implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Plane is running");
    }
}
代码语言:javascript
复制
import lombok.Data;

/**
 * Ship
 */
@Data
public class Ship implements Product{

    private String name;

    private String price;

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

接口与实现如下图所示

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

定义一个工厂方法接口

代码语言:javascript
复制
/**
 * IShop
 */
public interface IShop {

    /**
     * 获取商品
     */
    Product getProduct();
}

定义工厂接口实现

代码语言:javascript
复制
/**
 * Ship
 */
@Data
public class Ship implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Ship is running");
    }
}
代码语言:javascript
复制
/**
 * Plane
 */
@Data
public class Plane implements Product{

    private String name;

    private String price;

    @Override
    public void run() {
        System.out.println("the Plane is running");
    }
}
代码语言:javascript
复制
import lombok.Data;

/**
 * Car
 */
@Data
public class Car implements Product{

    private String name;

    private String price;

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

定义一个测试类

代码语言:javascript
复制

/**
 * test
 */
@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();
    }
}

运行结果

代码语言:javascript
复制
2021-01-10 15:01:59.394  INFO 21132 --- [           main] c.c.b.d.f.usedesign.impl.CarImpl         : this is car
2021-01-10 15:01:59.394  INFO 21132 --- [           main] c.c.b.d.f.usedesign.impl.ShipImpl        : this is Ship
2021-01-10 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-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 五角钱的程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、概述
  • 2、适用场景
  • 3、实例
    • 3.1 不使用工厂模式
      • 定义三个实体类
      • 定义接口和实现
      • 创建一个测试类
      • 执行结果
    • 3.2 使用工厂模式
      • 创建一个Product接口,定义run()方法
      • 定义三个实体类
      • 接口与实现如下图所示
      • 定义一个工厂方法接口
      • 定义工厂接口实现
      • 定义一个测试类
      • 运行结果
  • 4、分析
    • 实体类
      • 接口
        • 实现类
        • 5、总结
          • 优点:
            • 缺点:
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档