专栏首页老男孩成长之路用案例实战来给你讲解,设计模式中的工厂模式

用案例实战来给你讲解,设计模式中的工厂模式

工厂模式有啥用啊,我的项目没使用工厂模式也照样运行

这是我听过最令人哭笑不得的吐槽,这个程序猿的头发不知道有没有被自己薅秃

的确,项目中不使用工厂模式并不会影响项目的运行

但是,当项目后期需要二次开发时,代码的维护和修改的复杂度,绝对能让你恨不得把自己头发都薅秃

下面我们就来盘一盘工厂模式能解决哪些问题

简单工厂模式

实际案例

假如客户有这样一个需求,做一个用户订购手机来玩游戏的项目

项目中可以生产华为和小米的手机,生产的手机只能用来玩游戏,用户可以通过京东和淘宝来订购手机

需求中的一个前置条件是手机只能用来玩游戏,不能做别的事情。这就类似于一个规范,所有的手机都要遵守这个规范。

制定规范是java中接口的特性,所以我们要定义一个接口基类,叫做Phone,里面有一个玩游戏的方法play()

还要有华为手机和小米手机的类,分别叫做HuweiXiaomi,这两个手机类要遵循手机只能用来玩游戏这个规范,所以它们要实现Phone类,并完成play()方法

用java代码实现分别如下

phone基类

public interface Phone {
    void play();
}

华为手机类Huawei

public class Huawei implements Phone {
    @Override
    public void play() {
        System.out.println("华为手机玩游戏");
    }
}

小米手机类Xiaomi

public class Xiaomi implements Phone {
    @Override
    public void play() {
        System.out.println("小米手机玩游戏");
    }
}

用户可以通过京东和淘宝来订购手机,所以还要有京东和淘宝的类,分别叫做JingdongTaobao。类里面各有一个订购方法叫做order(),可以根据用户的喜好来订购不同的手机

如果用户喜欢华为则订购华为手机来玩游戏,如果用户喜欢小米则订购小米手机来玩游戏,其他的用户就不能玩游戏

因为京东类和淘宝类的代码逻辑一摸一样,这里只贴一下京东类的代码

public class Jingdong {
    public void order(String type) {
        Phone phone = null;
        if ("huawei".equals(type)) {
            phone = new Huawei();
            phone.play();
        } else if ("xiaomi".equals(type)) {
            phone = new Xiaomi();
            phone.play();
        } else {
            System.out.println("暂不支持");
        }
    }
}

这样我们就实现了客户的需求,而且没有使用任何设计模式。

项目虽然可以完美的运行,但是有一个问题值得我们思考,假如又增加了苹果手机,这时候我们的代码该怎么修改

首先,我们肯定是要增加苹果手机类IPhone,并且实现Phone基类

京东类中订购方法的逻辑需要做出相应的修改

淘宝类中订购方法的逻辑也需要做出相应的修改,修改的地方和京东类一模一样。这时我们就发现同样的代码需要修改两次。

如果订购类有很多,除了京东、淘宝,还有拼多多、微信商城等等。那就意味着同样的代码不止要修改两次,有多少个订购类就需要修改多少次

这个工作量是很大的,而且极其容易出错,就问你头秃不头秃

这时候就需要使用简单工厂模式来优化我们的代码

简单工厂模式就是创建一个工厂类,由这个类来封装实例化对象的行为

套用到这个例子中就是:创建一个工厂类,由工厂类来封装创建手机的逻辑。订购类从工厂类中获取手机对象直接使用,不再关心手机创建的过程

工厂类PhoneFactory用代码实现就是这样

public class PhoneFactory {
    public static Phone createPhone(String type) {
        Phone phone = null;
        if ("huawei".equals(type)) {
            phone = new Huawei();
        } else if ("xiaomi".equals(type)) {
            phone = new Xiaomi();
        } else if ("apple".equals(type)) {
            phone = new IPhone();
        } else {
            System.out.println("暂不支持");
        }
        return phone;
    }
}

京东、淘宝等订购类从工厂类里面获取手机对象后直接使用,不再关心手机的创建过程(京东和淘宝类的代码一样,这里只贴京东类的代码)

public class Jingdong {
    public void order(String type) {
        Phone phone = PhoneFactory.createPhone(type);
        if (phone != null) {
            phone.play();
        }
    }
}

这就实现了简单工厂模式,以后再需要增加手机型号时只需要修改工厂类就行了,其他代码不用修改

简单工厂模式总结

简单工厂模式就是创建一个工厂类,根据传入的参数类型来创建具体的产品对象,并返回产品对象的实例

主要适用于调用者不知道应该创建哪个具体的对象,只能根据传入的条件返回相应对象的场景

比如案例中,订购类是不知道要创建哪个手机对象的,只能根据用户提供的条件才能知道需要哪个手机对象

简单工厂模式的好处在于将对象的创建过程和使用过程进行解耦,减少新增具体产品时修改代码的复杂度

就像上面的例子一样,对象的创建过程由工厂类负责,订购类不需要关心对象是怎么创建的,只需要从工厂类获取对象来使用即可

当需要增加手机对象时,只需要修改工厂类,而不需要对每一个订购类进行修改

简单工厂模式的缺点在于每次新增具体产品时,都需要修改工厂类,这违背了设计模式中的开闭原则。而且当具体的产品比较多时,工厂类的if-else判断就会比较多,代码不美观

工厂方法模式

实际案例

基于刚才用户订购手机玩游戏的需求,我们稍微改动一下。

为了实现精准营销,京东、淘宝等商城分别上线了华为专卖店、小米专卖店和苹果专卖店

当用户进入华为专卖店,就默认用户要订购华为手机;当用户进入小米专卖店,就默认用户要订购小米手机;当用户进入苹果专卖店,就默认用户要订购苹果手机

这个需求用刚才我们讲的简单工厂模式也可以实现

但是简单工厂的缺点也很明显,当新增粉丝类型时需要修改工厂类,当粉丝类型过多时工厂类的逻辑就会比较繁杂

比如新增了vivo粉丝,工厂类就需要新增判断条件去创建vivo手机对象;新增了oppo手机,工厂类就要新增判断条件去创建oppo手机对象。一直不断的新增下去的话,就会导致工厂类的中的判断过多,代码很长,后期不容易维护

而且,简单工厂模式是适用于调用者不知道应该创建哪种对象的场景。

在这个需求中,京东等订购类中为不同的粉丝提供了专卖店,假如专卖店是订购类中的一个方法的话,在专卖店这个方法中是知道应该创建什么样的对象的。比如,在华为手机的订购方法中,是知道要创建华为手机对象的

所以,这个需求可以用工厂方法模式来实现

工厂方法模式和简单工厂模式相似,也需要有一个工厂类。不过在工厂方法模式中,工厂类不再负责创建对象。因为在每个订购方法中已经知道应该创建哪个手机对象,所以创建对象的逻辑下沉到订购类的方法中

工厂类只负责制定规范,来约束每个产品的具体行为,所以工厂类是一个接口基类。每个对应的产品需要有一个自己的工厂,来继承这个基类,达到约束自身行为的目的

这个需求中工厂基类规定每个工厂只能有一个方法,这个方法的作用就是创建手机对象

工厂基类PhoneFactory用代码实现

public interface PhoneFactory {
   Phone createPhone();
}

华为工厂类用代码实现

public class HuaweiFactory implements PhoneFactory {
   @Override
   public Phone createPhone() {
      return new Huawei();
   }
}

小米工厂类用代码实现

public class XiaomiFactory implements PhoneFactory {
   @Override
   public Phone createPhone() {
      return new Xiaomi();
   }
}

在订购类中,不同的订购方法调用不同的工厂获取对象。比如京东订购类的代码如下(淘宝订购类处理逻辑类似,这里不再贴淘宝类的代码)

public class Jingdong {
    // 华为粉丝订购华为手机
    public void orderHuawei() {
        PhoneFactory phoneFactory = new HuaweiFactory();
        Phone phone = phoneFactory.createPhone();
        phone.play();
    }
    // 小米粉丝订购小米手机
    public void orderXiaomi() {
        PhoneFactory phoneFactory = new XiaomiFactory();
        Phone phone = phoneFactory.createPhone();
        phone.play();
    }
}

这样我们就用工厂方法模式实现了为不同粉丝订购不同手机的需求

工厂方法模式总结

工厂方法模式是定义一个工厂接口基类,基类中定义一个创建产品的抽象方法。每个产品需要有自己的工厂来实现这个基类,并完成创建对应产品实例的方法,由具体的产品调用该方法来创建对象

它主要适用于调用者已经明确知道需要创建哪一个具体产品的场景

比如,针对华为的粉丝,已经明确知道要创建华为的手机产品

工厂方法模式的优势在于完全符合了开闭原则,在新增产品时不需要再改动已存在的代码,使工厂类和产品类的代码完全解耦,更利于程序的扩展

他的缺点也很明显,当新增产品时,需要同时新增产品类和工厂类,导致系统中的类是成对增加,增加了系统的复杂度

抽象工厂模式

实际案例

基于工厂方法模式的案例,我们再进一步扩展

用户不单单想订购手机来玩游戏,还想订购ipad和电脑

可以用刚才讲的工厂方法模式来实现:我们不仅需要提供手机工厂的基类,还需要提供ipad工厂基类和电脑工厂基类,并且为每个工厂基类提供具体的工厂实现类

订购类方法中,根据不同的需求来创建不同的产品供用户使用

这样实现的代码没有问题,但是不符合我们真实开发中的业务场景

在实际业务场景中,京东商城的华为专卖店想要订购手机不需要到华为公司的手机部门去订购吧?想要订购ipad不需要到华为公司的ipad部门订购吧?想要订购电脑也不需要到华为公司的电脑部门订购吧?

京东商城的华为专卖店应该只负责和华为公司对接,和具体的业务部门没关系。专卖店想要订购某个产品去告诉华为公司,由公司去给具体的业务部门沟通

所以,从实际的使用场景出发,我们的代码应该这样设计

不再使用单独的手机工厂、ipad工厂和PC工厂,而是把同一个厂家作为工厂,由工厂分别创建不同的产品

Factory基类实现代码如下

public interface Factory {
    Phone createPhone();
    IPad createIPad();
    PC createPC();
}

华为工厂类实现代码如下

public class HuaweiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new HuaweiPhone();
    }
    @Override
    public IPad createIPad() {
        return new HuaweiIPad();
    }
    @Override
    public PC createPC() {
        return new HuaweiPC();
    }
}

小米工厂实现代码如下

public class XiaomiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new XiaomiPhone();
    }
    @Override
    public IPad createIPad() {
        return new XiaomiIPad();
    }
    @Override
    public PC createPC() {
        return new XiaomiPC();
    }
}

在京东订购类中,我们只需要创建对应的工厂对象,由工厂对象创建不同的产品

public class Jingdong {
    // 华为粉丝订购手机、ipad、电脑
    public void orderHuawei() {
        Factory factory = new HuaweiFactory();
        Phone phone = factory.createPhone();
        phone.play();
        IPad ipad = factory.createIPad();
        ipad.play();
        PC pc = factory.createPC();
        pc.play();
    }
    // 小米粉丝订购手机、ipad、电脑
    public void orderXiaomi() {
        Factory factory = new XiaomiFactory();
        Phone phone = factory.createPhone();
        phone.play();
        IPad ipad = factory.createIPad();
        ipad.play();
        PC pc = factory.createPC();
        pc.play();
    }
}

这样我们就用抽象工厂模式实现了用户订购手机、ipad和电脑的需求

抽象工厂模式总结

抽象工厂模式是将具有一定共性的产品封装到一块,由工厂类分别为这些产品提供创建对象的方法,调用者可以根据不同的需求调用工厂类的具体方法来获得产品实例

比如案例中华为的手机、ipad和电脑都属于华为公司产品,所以可以由华为工厂类来负责分别创建不同的对象

它的优势在于将具有一定共性的产品集合封装到一起,在实际开发中更符合具体的业务场景

他的缺点就是降低了系统的扩展性,当新增产品时需要修改工厂类,在工厂类的基类和实现类中都需要增加对应的方法

比如说,用户也想订购VR眼镜来玩游戏。那么工厂基类中需要增加创建VR眼镜的方法,所有的工厂实现类中都需要增加对该方法的实现,系统扩展性比较差

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 实例解析C#设计模式编程中简单工厂模式的使用

    简单工厂模式的介绍   说到简单工厂,自然的第一个疑问当然就是什么是简单工厂模式了?在现实生活中工厂是负责生产产品的,同样在设计模式中,简单工厂模式我们也可以理...

    zls365
  • PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】

    多数人都是从单例模式的字面上的意思来理解它的用途, 认为这是对系统资源的节省, 可以避免重复实例化, 是一种”计划生育”. 而PHP每次执行完页面都是会从内存中...

    砸漏
  • 三大JS设计模式(工厂 单例 适配器)模式。通俗易懂理解等你来理解

    //核心是工厂顾名思义是做东西的地方,工厂模式也就是我把我想要的东西叫工厂做,做好了给我就是了呀,(我并不需要知道怎么做哈)

    贵哥的编程之路
  • 手把手教你应用三种工厂模式在SpringIOC中创建对象实例【案例详解】

    工厂模式相信很多小伙伴们都有听说过,但是工厂模式在Java中的具体使用你有了解过吗?今天在这里和大家讲一下在Spring中如何使用三种工厂模式(静态工厂、实例工...

    灰小猿
  • 公司终于决定放弃传统微服务,全面拥抱 DDD!

    前段时间,参加了一场闭门技术交流会,讨论的热点是微服务,话题集中在微服务架构拆分到底应该拆多细。

    Guide哥
  • 5G 时代互联网行业有什么新机遇?需要学习哪些知识?

    近日,腾讯无线网络与物联网技术负责人李秋香与高校科研教授、产业链、运营商等各行业的嘉宾一起参与了知乎「 科技共振之 5G+ 」活动,除了专业的5G探讨,也聊了不...

    云加社区
  • C#设计模式开启闯关之路

      这是一条望不到尽头的编程之路,自踏入编程之路开始。就面临着各式各样的挑战,而我们也需要不断的挑战自己、不断学习充实自己、打好坚实的基础。以使我们可以走的更远...

    小世界的野孩子
  • 写代码写了好几年,才发现自己天天都在用设计模式!

    本系列文章主要围绕程序员,特别是Java或者后端程序员必须掌握的一些技术和技能,这些文章都是结合我个人的编程学习经历,总结和沉淀下来的方法论。作者目前在阿里做J...

    黄小斜学Java
  • 常用设计模式小结

    现在你已经准备好迎接一个充满设计模式的崭新世界。 但是,在你打开所有的机会大门之前,我们需要告诉你一些即将在真实世界中遇到的细节--没错,外面的世界还是比较复杂...

    程序员小跃
  • 从外包到大厂的逆袭!安卓开发5年,一年蛰伏后面试成offer收割机,入职腾讯定薪20*15

    14年刚毕业的时候,Android开发市场发展火热,无数人员涌入Anroid开发行业,人员增长率快,自然市场竞争力就大。当因为学历不高、职业技能不熟悉再加上没经...

    Android技术干货分享
  • 你真的会用简单工厂吗?

    在项目中经常会碰到工厂模式,不光在项目中有在阅读源码的时候也一定少不了工厂模式。在我们上上一篇文章分布式定时任务Quartz中创建触发器也是通过Quartz所提...

    乱敲代码
  • 创建型模式:抽象工厂

    Provide an interface for creating families of related or dependent objects witho...

    LieBrother
  • 领域驱动设计的不确定性

    本文是我即将在GitChat发布的领域驱动设计第二篇「领域驱动战术设计实践」的开篇词。本课程预计会在5月初发布,内容承接「领域驱动战略设计实践」,敬请关注。

    张逸
  • 软硬解耦,大道至简

    鹅厂网事
  • 企业用户ERP选型还需“门当户对”,必看 50 谏言!

    T客汇官网:tikehui.com 译者 |杨丽 ? 选择一款合适的 ERP 软件并非易事。 首先,ERP 系统的概念不断扩大,涉及的领域也在逐渐扩张。企业选购...

    人称T客
  • 和 lvgo 一起学设计模式(十一)结构型之享元模式

    这个设计模式在 GOF 的书中是用 flyweight 这个词来定义这种模式的,然后翻译成中文就叫 享元 了,讲真挺不自在,首先这个词是一个自造词(享元)

    星尘的一个朋友
  • 前端设计模式之工厂模式

    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

    Cookieboty
  • Python不香吗,为什么还要学数据分析?

    有读者问我,看到现在大厂都在招数据分析师,薪资也非常有吸引力,我会用 SQL 和 Excel,还会一点 Python,能不能去应聘?

    刘早起
  • 企业AD架构规划设计详解

    这个章节主要讲Active Directory 域服务概述及相关概念,设计步骤及AD常见的规划设计TOP方案,每种架构TOP方案的特定及优缺点。

    用户7118337

扫码关注云+社区

领取腾讯云代金券