Java设计模式——工厂模式_java工厂设计模式-程序员宅基地

技术标签: java  设计模式  开发语言  

设计模式系列文章


前言

最近在学习一些Java设计模式的概念,设计模式诞生的目的,我认为是可以使得写出的代码具有更好的逻辑性,减少了大量冗余代码来进行重复而繁琐的操作,也更好的提升了复用性。所以学习并且能够使用合理的设计模式可以让我们的代码更加美观,优雅,结构更加清晰。

本次内容对Java中的工厂模式进行讲解,工厂模式又可以分为三种

                              ” 简单工厂,工厂方法, 抽象工厂 ”


一、简单工厂模式

工厂模式,主要用于创建对象时的一系列操作。

在我们平时创建对象的时候,一般使用New关键字来进行创建。

ClassA a = new ClassA();
ClassB b = new ClassB();

 我们使用New关键字创建对象,会根据括号内的参数在构造函数里对实例化对象进行初始化。

然而,我们创建一个对象的时候,可能需要对他进行一些初始化操作,例如查询数据库,对属性赋值等等。如果我们把这些操作也全部写到构造函数中。那构造函数就变得很长很长,可读性大大降低。

针对这种情况,我们可以引入 ” 工厂 “ 的概念,我们不通过New关键字去创建对象了,我们直接去创建一个工厂,让工厂去帮我们创建对象。

例如,我们创建了一个专门生产手机的工厂,这个工厂可以生产梨子手机,菠萝手机。

那么首先我们要创建梨子手机和菠萝手机这两个类,这里我实现了一个Phone接口,表明梨子手机和菠萝手机都是一个 ” Phone “类型的类,然后我们在创建的时候返回Phone类型的就可以了。

public interface Phone {
    void show();
}

public class LiPhone implements Phone {
    @Override
    public void show() {
        System.out.println("我是梨子手机");
    }
}

public class BoPhone implements Phone {
    @Override
    public void show(){
        System.out.println("我是菠萝手机");
    }

}

 然后我们再创建一个手机工厂,来生产手机。

这里应该很通俗易懂,我们再创建手机的时候,只需要给定规定好的number,工厂就知道该生产什么手机了,然后也可以按照我们的意愿去进行初始化。

public class PhoneFactory{

    public Phone createPhone(Integer number) {
        Phone phone = null;
        if(number == 1){
            phone = new LiPhone();
            // .....
            // 梨子手机的初始化代码
        }else if(number == 2){
            phone =  new BoPhone();
            // .....
            // 菠萝的初始化代码
        }
        return phone;
    }
}

然而这么做其实又会衍生出一个问题,那就是当我们有很多牌子手机的时候,比如我们还有锤子手机,番茄手机,土豆手机。那我们每多一个手机,就要去修改一次手机工厂的 if else 判断,这违背了设计模式的一个原则 “ 对修改关闭,对拓展开启 ”

(注:所谓面向对象的开放-封闭原则,就是在程序中对“扩展”开放,对“修改”封闭。如果每次业务改动都要增加新的if-else,就涉及对旧有代码的修改,不但容易出错,可读性也不好。)

那么怎么解决呢,我们可以使用下面提到的工厂方法模式。

二、工厂方法模式

前面我们提到,为了解决简单工厂模式中通过工厂创建对象 if esle 语句过多的问题可以使用工厂方法模式。而工厂方法模式的主要原理就是,我们把每一个要创建的产品对象独立分配一个工厂,提取一个工厂接口出来,独立分配的工厂作为工厂接口的实现类,这样我们在创建工厂——再通过工厂创建对象的过程中,工厂就是唯一确定了的,所以创建的对象也是唯一确定的,不需要再使用过多的判断语句了。

所以我们对之前的工厂类进行修改先.

现在我们提取出了一个工厂接口,接口中有生产手机的方法,然后我们为梨子手机和菠萝手机都创建一个工厂类去实现接口,在实现类的 createPhone 方法中创建手机,这样如果我们以后有了其他手机,只需要再增加手机的工厂类去实现接口就可以了。

public interface PhoneFactory {
    Phone createPhone();
}

public class LiFactory implements PhoneFactory{

    @Override
    public Phone createPhone() {
        Phone phone =  new LiPhone();
        // .....
        // 初始化代码
        return phone;
    }
}

public class BoFactory implements PhoneFactory{

    @Override
    public Phone createPhone() {
        Phone phone =  new BoPhone();
        // .....
        //  初始化代码
        return phone;
    }
}

测试方法

public class Test {

    public static void main(String[] args) {
        PhoneFactory factoryA = new LiFactory();
        PhoneFactory factoryB = new BoFactory();
        Phone phoneA = factoryA.createPhone();
        Phone phoneB = factoryB.createPhone();
        phoneA.show();
        phoneB.show();
    }
}

 输出:

我是梨子手机

我是菠萝手机

那么, 其实我们可以显而易见的发现,工厂方法模式虽然可以确保我们每一个手机对应一个工厂,而且需要创建手机的时候只需要通过对应工厂创建就可以了,但是这样随着我们的产品越来越多,工厂的实现类也越来越多,看的人头都晕了。

那么,我们可以使用 “ 抽象工厂 ”模式来解决这个问题。比如我们的梨子手机和菠萝手机分别来自梨子厂和菠萝厂。那梨子厂和菠萝厂它们也有远大的理想!!他们不想只做手机! 他们要搞吧来福,搞把AK,做大做强!

梨子厂要做手机和电脑,菠萝见状,心想那我指定也得卷起来啊,于是菠萝老板下令,我们也要做手机和电脑!

三、抽象工厂模式

从上面的情景我们可以分析得到,梨子厂和菠萝厂都不甘现状,他们不禁想做手机,还想做电脑。

那我们需要去创建一个手机厂的同时再去创建一个电脑厂吗??

那当然不需要了,我们可以创建一个工厂接口,这个工厂既可以做手机,又可以做电脑

我们再创建实现类工厂,梨子厂和菠萝厂。因为梨子厂和菠萝厂都实现了工厂接口,所以他们都有创建手机和电脑的流水线(方法)

那就简单了,我们在各自的流水线中创建自己的产品不就行了嘛

直接上代码!!

哦不 先上个图 画的丑陋,帅哥美女们将就看看

上代码!!!

首先安排两个产品的接口,手机接口和电脑接口,以及他们的实现类。

public interface Phone {
    void showPhone();
}

public class LiPhone implements Phone {
    @Override
    public void showPhone(){
        System.out.println("我是梨子手机");
    }
}

public class BoPhone implements Phone {
    @Override
    public void showPhone(){
        System.out.println("我是菠萝手机");
    }
}

public interface Computer {
    void showComputer();
}

public class LiComputer implements Computer {
    @Override
    public void showComputer() {
        System.out.println("我是梨子电脑");
    }
}

public class BoComputer implements Computer {
    @Override
    public void showComputer() {
        System.out.println("我是菠萝电脑");
    }
}

然后再安排一下我们的重头戏,抽象工厂。

public interface IFactory {
    //创建口罩
    Phone createPhone();
    //创建防护服
    Computer createComputer();
}

public class LiFactory implements IFactory {
    @Override
    public Phone createPhone() {
        Phone phone =  new LiPhone();
        // .....
        //  初始化代码
        return phone;
    }

    @Override
    public Computer createComputer() {
        Computer computer =  new LiComputer();
        // .....
        // 初始化代码
        return computer;
    }
}

public class BoFactory implements IFactory {
    @Override
    public Phone createPhone() {
        Phone phone =  new BoPhone();
        // .....
        //  初始化代码
        return phone;
    }

    @Override
    public Computer createComputer() {
        Computer computer =  new BoComputer();
        // .....
        // 初始化代码
        return computer;
    }
}

 最后测试一下来看看

public class Test {

    public static void main(String[] args) {
        IFactory factoryA = new LiFactory();
        IFactory factoryB = new BoFactory();
        //创建低端口罩
        Phone phoneA = factoryA.createPhone();
        //创建高端口罩
        Phone phoneB = factoryB.createPhone();
        //创建低端防护服
        Computer computerA = factoryA.createComputer();
        //创建高端防护服
        Computer computerB = factoryB.createSuit();

        phoneA.showPhone();
        phoneB.showPhone();
        computerA.showComputer();
        computerB.showComputer();
    }
}

 输出:

我是梨子手机

我是菠萝手机

我是梨子电脑

我是菠萝电脑

大功告成~  


总结

现在越来越多Java开发方面的工作在招聘的要求上都会要求应聘者要熟知常见的设计模式,以及在面试的过程中也经常会问道设计模式相关的知识,所以设计模式的学习是非常重要的,而且学习了还要会融会贯通,在写代码的时候,遇到有重复的代码就可以思考一下是否可以将重复的代码抽取出来进行封装或者其他操作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_56032340/article/details/123574551

智能推荐

二、ORB-SLAM3编译安装和运行(Ubuntu22.04)_ubuntu22.04安装orb-slam3-程序员宅基地

文章浏览阅读1.1k次,点赞26次,收藏23次。(一条一条的)执行脚本中每条指令,并根据自己虚拟机分配的核数选择make后面的核数进行编译【首先尝试原来的脚本命令,运行不动到自动结束进程的地步的话改成make -j4,还运行不动直接改成make,这样会运行的慢一些但至少不卡,慢慢等吧,我的是Sophus运行那一块和最后一句指令卡住了,吐槽一下:天啦噜,运行不动啊真的会哭】”“无法打开虚拟机,是否从库中移除××”?还是这句话:我遇到的问题写在了后面,如果安装遇到问题可以先看看其中是否有相同的问题,是否有其解决方法。对于我年纪大了点的电脑太不容易了啊!_ubuntu22.04安装orb-slam3

Javascript基础系列之闭包_js闭包-程序员宅基地

文章浏览阅读730次,点赞2次,收藏2次。在上面的代码示例中,`a`函数定义了一个名为`aa`的变量和一个名为`b`的函数,`b`函数引用了`aa`变量,因此JavaScript引擎会保留`a`函数的作用域链,`b`函数可以访问`a`函数的执行上下文,`b`函数内用到了外部函数`a`的变量`aa`,在`a`函数调用结束后该函数执行上下文会销毁,但会保留一部分留在内存中供`b`函数使用,这就形成了闭包。这种函数嵌套和变量共享的方式就是闭包的核心概念。并且 `fun.Closure` 中的内容是 `a` 和 `b` 两个变量,并没有 `c`。_js闭包

windows安装MySQL到D盘_mysql怎么安装到d盘-程序员宅基地

文章浏览阅读1.8w次,点赞61次,收藏181次。将MySQL安装到D盘(你想哪个盘就哪个盘)_mysql怎么安装到d盘

已拒绝虚拟机配置。请参见浏览器控制台-程序员宅基地

文章浏览阅读1.5k次。创建虚拟机时报错用ESXI6.7.0版本,存储用服务器挂载NFS后,在服务器上创建虚拟机出现该错误,在本地创建虚拟机没有报错。_已拒绝虚拟机配置。请参见浏览器控制

大数据的关键技术(一)-程序员宅基地

文章浏览阅读333次,点赞5次,收藏5次。(6)MapReduce 的功能:①、

【已解决】JSON.parse 返回[Object Object] 问题_parse后返回的对象是[object object]-程序员宅基地

文章浏览阅读5.8k次,点赞6次,收藏4次。JSON.parse返回[Object Object]问题,【已解决】:如果是console.log输出JSON.parse的结果的话, 查看下console.log里是否_parse后返回的对象是[object object]

随便推点

如何通过navicat连接SQL Server数据库_navicat连接sqlserver-程序员宅基地

文章浏览阅读1w次,点赞16次,收藏39次。本文介绍如何通过Navicat 连接SQL Server数据库。_navicat连接sqlserver

基于微信小程序的中华美食分享系统设计与实现_基于微信小程序的食谱共享系统-程序员宅基地

文章浏览阅读853次,点赞7次,收藏10次。如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费。_美食分享系统设计

逆向实战(1)-某国石油招标投标网站研究(非对称加密、图片计算验证码)_计算验证码逆向-程序员宅基地

文章浏览阅读965次,点赞2次,收藏2次。js逆向某石油招投标网站;RSA加密;图片验证码;_计算验证码逆向

我的世界2D英文版Scratch源文件_paper minecraft scratch源代码-程序员宅基地

文章浏览阅读575次,点赞7次,收藏6次。我的世界2D英文版Scratch源文件为sb3文件。_paper minecraft scratch源代码

YOLOv5改进算法之添加CA注意力机制模块_yolov5添加注意力机制-程序员宅基地

文章浏览阅读7.8k次,点赞93次,收藏180次。YOLO_yolov5添加注意力机制

python-函数参数类型检查_python 判断参数类型-程序员宅基地

文章浏览阅读5.1k次。python在3.5后引入了参数类型注解,例:def add(x:int,y:int)->int:#对x,y和返回值都进行注释,为int类型 return x + y注:注解是对函数参数和返回值的‘注释’,没有强制定义的作用(因为python是动态语言啊)那么既然注解不能强制定义类型,在函数调用中怎么判断传入的参数是否是我想要的呢?在次引入python的inspect模块ins..._python 判断参数类型