戏说设计模式——工厂模式

目录

一、工厂模式是什么?

二、准备工作

三、传统的工厂模式

1.简单工厂

2.工厂方法模式

3.抽象工厂

四、用函数式接口写工厂模式

小结


一、工厂模式是什么?

        说到工厂模式,就要讲到什么是工厂;提到工厂,就要讲到社会大生产的分工;提到分工...那就要从人类起源讲起了,一篇文章就不够絮叨的了。简单一句话,工厂就是为了提高生产效率,将生产与使用的过程分开的一个场所,具体到java开发中来讲就是把对象的创建过程和使用过程分开的一种表现形式。

二、准备工作

        我们以兵器制造为例,先创建两个兵器类:机枪&坦克

package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:25
 * @description 兵器
 */
public interface Weaponry {
    void fire();

    void ammunitionLoading();

    void maintenance();
}
package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:27
 * @description 枪
 */
public class Gun implements Weaponry{
    @Override
    public void fire() {
        System.out.println("机枪开火:扣动扳机。。。");
    }

    @Override
    public void ammunitionLoading() {
        System.out.println("机枪装弹:把子弹装进弹夹。。。");
    }

    @Override
    public void maintenance() {
        System.out.println("机枪保养:拆开擦一擦。。。");
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:27
 * @description 坦克
 */
public class Tank implements Weaponry{
    @Override
    public void fire() {
        System.out.println("坦克开火:开炮。。。");
    }

    @Override
    public void ammunitionLoading() {
        System.out.println("坦克装弹:装进掷弹筒。。。");
    }

    @Override
    public void maintenance() {
        System.out.println("坦克保养:洗刷刷。。。");
    }
}

三、传统的工厂模式

        当不使用工厂模式时,大兵们只有自己动手,才能丰衣足食,自己造枪,自己造炮

package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午2:53
 * @description
 */
public class Soldier {
    public static void main(String[] args) {
        //造枪-保养-装弹-开火
        Gun gun = new Gun();
        gun.maintenance();
        gun.ammunitionLoading();
        gun.fire();
        //造炮-保养-装弹-开火
        Tank tank = new Tank();
        tank.maintenance();
        tank.ammunitionLoading();
        tank.fire();
    }
}

        我仅代表和平战士们同情这些大兵。。。

1.简单工厂

        简单工厂模式提供了最基础的工厂模型,它把所有的生产流水线集中到一个车间中完成。大兵向工厂提出自己的需要,由工厂根据需要在相应流水线生产武器给大兵使用。

package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:24
 * @description 兵工厂
 */
public class Arsenal {
    public Weaponry create(String weapon) {
        switch (weapon) {
            case "gun" :
                return new Gun();
            case "tank" :
                return new Tank();
        }
        return null;
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午2:53
 * @description
 */
public class Soldier {
    public static void main(String[] args) {
        //造枪-保养-装弹-开火
        Arsenal arsenal = new Arsenal();
        Weaponry gun = arsenal.create("gun");
        gun.maintenance();
        gun.ammunitionLoading();
        gun.fire();
        //造炮-保养-装弹-开火
        Weaponry tank = arsenal.create("tank");
        tank.maintenance();
        tank.ammunitionLoading();
        tank.fire();
    }
}

        简单工厂初步实现了让大兵不再关注武器生产这事了,可以专注于发挥武器的最大威力。但是,对于工厂来说,在一间厂房里为每个武器都创建一条流水线是不明智的。武器的种类是在扩展的,抛开厂房扩建的成本不算,厂房扩建中也许会影响到当前流水线的正常使用,即使扩建完成,也保不齐哪天流水线就串了,维护成本比较高(你懂的)。

2.工厂方法模式

package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:24
 * @description 兵工厂
 */
public interface Arsenal {
    Weaponry create();
}
package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午8:28
 * @description 机枪车间
 */
public class GunWorkshop implements Arsenal{
    @Override
    public Weaponry create() {
        return new Gun();
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午8:28
 * @description 装甲车间
 */
public class TankWorkshop implements Arsenal{
    @Override
    public Weaponry create() {
        return new Tank();
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午2:53
 * @description
 */
public class Soldier {
    public static void main(String[] args) {
        //造枪-保养-装弹-开火
        Arsenal gunArsenal = new GunWorkshop();
        Weaponry gun = gunArsenal.create();
        gun.maintenance();
        gun.ammunitionLoading();
        gun.fire();
        //造炮-保养-装弹-开火
        Arsenal tankArsenal = new TankWorkshop();
        Weaponry tank = tankArsenal.create();
        tank.maintenance();
        tank.ammunitionLoading();
        tank.fire();
    }
}

        工厂方法模式解决了简单工厂扩展和维护(开闭原则:略)的问题,但是,随着专业化分工的发展,枪托,枪管等零部件的生产应该由一部分人专门负责,而流水线只负责零部件的组装。这样既减少了这部分人学习的压力, 又能让他们在专攻领域精益求精,何乐不为?专业细化的分工,也诞生了一部分零部件生产厂商,而同样的零部件也可以供应多种兵器的生产。我们来看看抽象工厂是如何做的

        同理,在Java项目开发中,对于工厂方法模式于抽象工厂的区别,用产品等级结构和产品族来描述

3.抽象工厂

        首先,我们创建机枪创建两个零件枪管&弹夹

package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:28
 * @description 枪管
 */
public interface Barrel {
    /**
     * 口径
     */
    void diameter();
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:40
 * @description
 */
public class Barrel762 implements Barrel{
    @Override
    public void diameter() {
        System.out.println("口径:7.62mm");
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:40
 * @description
 */
public class Barrel1143 implements Barrel{
    @Override
    public void diameter() {
        System.out.println("口径:11.43mm");
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:28
 * @description 弹夹
 */
public interface Clip {
    /**
     * 类型
     */
    void type();
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:36
 * @description
 */
public class EnBlockClip implements Clip{
    @Override
    public void type() {
        System.out.println("漏夹");
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午12:36
 * @description
 */
public class StripperClip implements Clip{
    @Override
    public void type() {
        System.out.println("桥夹");
    }
}

        加工厂拿到图纸后决定为M16和汤姆逊机枪引进几条流水线生产这些零部件

package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午2:03
 * @description 抽象零部件兵工厂
 */
public interface AbstractPartArsenal {
    Barrel createBarrel();

    Clip createClip();
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午2:12
 * @description M16零部件加工流水线
 */
public class M16PartArsenal implements AbstractPartArsenal {
    @Override
    public Barrel createBarrel() {
        return new Barrel762();
    }

    @Override
    public Clip createClip() {
        return new StripperClip();
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午2:12
 * @description 汤普逊零部件加工流水线
 */
public class ThompsonPartArsenal implements AbstractPartArsenal {
    @Override
    public Barrel createBarrel() {
        return new Barrel1143();
    }

    @Override
    public Clip createClip() {
        return new StripperClip();
    }
}

        下面,我们试着构建两个组装车间把枪械组装起来

package com.elean.design;

/**
 * @auther Elean
 * @date 19/6/2024 下午9:27
 * @description 枪工厂
 */
public interface GunArsenal {
    void assemble(AbstractPartArsenal part);
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午3:43
 * @description
 */
public class M16GunArsenal implements GunArsenal{
    @Override
    public void assemble(AbstractPartArsenal part) {
        Barrel barrel = part.createBarrel();
        Clip clip = part.createClip();
        System.out.println("组装M16:");
        barrel.diameter();
        clip.type();
    }
}
package com.elean.design;

/**
 * @auther Elean
 * @date 21/6/2024 下午3:43
 * @description
 */
public class ThompsonGunArsenal implements GunArsenal{
    @Override
    public void assemble(AbstractPartArsenal part) {
        Barrel barrel = part.createBarrel();
        Clip clip = part.createClip();
        System.out.println("组装汤姆逊:");
        barrel.diameter();
        clip.type();
    }
}

        经历了这么多的加工和组装的工序,大兵们总算拿到他们心仪的武器了。值得庆幸的是,他们完全不用关心生产的全过程

package com.elean.design;

/**
 * @auther Elean
 * @date 20/6/2024 下午2:53
 * @description
 */
public class Soldier {
    public static void main(String[] args) {
        AbstractPartArsenal m16Part = new M16PartArsenal();
        GunArsenal m16 = new M16GunArsenal();
        m16.assemble(m16Part);
        AbstractPartArsenal gunArsenal = new ThompsonPartArsenal();
        GunArsenal thompson = new ThompsonGunArsenal();
        thompson.assemble(gunArsenal);
    }
}

四、用函数式接口写工厂模式

        在实际开发过程中,我们对工厂模式的应用往往是从框架的角度出发的,但对于独立开发的程序员来说可能更加注重某个模块的功能实现。如果在功能模块的开发过程中,需要根据不同的入参条件使用不同的方法,这时候我们就需要对工厂模式的原理进行生活,以实现使用者只关注使用而忽略复杂的实现逻辑的过程,由此,我们可以结合函数式接口,对工厂模式进行杂交、进化

package com.elean;

/**
 * @auther Elean
 * @date 19/6/2024 下午5:48
 * @description
 */
public class DemoUtil {
    public static Object calcOne(Object in) {
        return "This is index one result " + in;
    }

    public static Object calcTwo(Object in) {
        return "This is index two result " + in;
    }

    public static Object calcThree(Object in) {
        return "This is index three result " + in;
    }

    public static Object error(Object in) {
        throw new RuntimeException("No calc method to " + in);
    }
}
package com.elean;

import java.util.function.Function;
import java.util.stream.Stream;

/**
 * @auther Elean
 * @date 19/6/2024 下午5:47
 * @description
 */
public enum DemoEnum {

    INDEX_ONE("INDEX_ONE", DemoUtil::calcOne),
    INDEX_TWO("INDEX_TWO", DemoUtil::calcTwo),
    INDEX_THREE("INDEX_THREE", DemoUtil::calcThree),
    ERROR("Error", DemoUtil::error)
    ;

    private String code;
    private Function func;

    DemoEnum(String code, Function func) {
        this.code = code;
        this.func = func;
    }

    public Function getFunc() {
        return func;
    }

    public static DemoEnum type(String code) {
        return Stream.of(values())
                .filter(e -> e.code.equals(code))
                .findFirst()
                .orElse(ERROR);
    }
}
package com.elean;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<String> codes = new ArrayList<>();
        codes.add("INDEX_ONE");
        codes.add("INDEX_TWO");
        codes.add("INDEX_THREE");

        codes.stream()
                .map(e -> DemoEnum.type(e).getFunc().apply(e))
                .forEach(System.out::println);
    }
}

小结

        程序员是网络生态世界的搬运工。在开发过程中,使用开发模式往往能够让代码看起来更加整洁、易维护,但并不是任何场景都适合生搬硬套的把整个开发模式搬过来。在合适的场景,进行一定的拓展和加工创新,才能让我们的项目更加有灵魂!

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值