肝一肝设计模式【二】-- 工厂模式

系列文章目录

肝一肝设计模式【一】-- 单例模式 传送门
肝一肝设计模式【二】-- 工厂模式 传送门


文章目录

  • 系列文章目录
  • 前言
  • 一、简单工厂模式
  • 二、工厂方法模式
  • 三、抽象工厂模式
  • 写在最后


前言

在实际开发过程中,构建对象往往使用new的方式来构建,但随着开发时间的拉长,构建对象的逻辑慢慢会在很多类里使用,那就势必会产生大量的重复代码,那就意味着难以维护,所以我们想把创建对象的代码和业务逻辑分离,并通过一个统一的接口创建对象,然后把创建对象的逻辑封装起来,而这些就是工厂模式所解决的问题


一、简单工厂模式

我们拿动物世界举个栗子(最近陪女鹅看动画片看太多,脑子第一时间想到的只有动物o(* ̄3 ̄)o )
在这里插入图片描述
我们先定义一个Animal接口

public interface Animal {
    
    public void eat();
}

然后再创建两个实现类兔子和老虎

public class Rabbit implements Animal {

    @Override
    public void eat() {
        System.out.println("我是兔子,我吃胡萝卜");
    }
}
public class Tiger implements Animal {

    @Override
    public void eat() {
        System.out.println("我是老虎,我吃肉");
    }
}

再创建一个AnimalFactory工厂类,有两种方式实现:

  1. 使用逻辑判断方式
public class AnimalFactory {

    public Animal create(String name) {
        if("rabbit".equals(name)) {
            return new Rabbit();
        } else if("tiger".equals(name)) {
            return new Tiger();
        } else {
            System.out.println("啥也不是");
            return null;
        }
    }
}

然后我们测试一下:

public class SimpleFactoryTest {
    public static void main(String[] args) {
        AnimalFactory factory = new AnimalFactory();
        factory.create("rabbit").eat();
    }
}

也可将AnimalFactory工厂类的create()方法改为静态方法,这样调用就更方便一点。

  1. 使用反射方式
public class AnimalFactory {

    public Animal create(Class<? extends Animal> c){
	    try {
	        if (null != c) {
	            return c.newInstance();
	        }
	    }catch (Exception e){
	        e.printStackTrace();
	    }
	    return null;
	}
}

我们测试一下:

public class SimpleFactoryTest {
    public static void main(String[] args) {
        AnimalFactory factory = new AnimalFactory();
        Animal animal = factory.create(Tiger.class);
	    animal.eat();
	}
}

简单工厂模式实质:是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

二、工厂方法模式

在简单的工厂模式里,我们创建了一个类似工具的类来创建相应的具体类对象,但正因为其太过简单,不符合开闭原则。
工厂方法模式就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层 + 具体的工厂子类层。

在这里插入图片描述
我们上面的工厂类进行拆分

  • AnimalFactory(抽象工厂)
public abstract class AnimalFactory {
    public abstract Animal create();
}
  • RabbitFactory(具体的工厂子类)‘
public class RabbitFactory extends AnimalFactory {
    @Override
    public Animal create() {
        return new Rabbit();
    }
}
  • TigerFactory(具体的工厂子类)
public class TigerFactory extends AnimalFactory {
    @Override
    public Animal create() {
        return new Tiger();
    }
}

测试一下

public class FactoryMethodTest {
    public static void main(String[] args) {
        AnimalFactory factory = new RabbitFactory();
	    Rabbit rabbit = factory.create();
	    rabbit.eat();
	}
}

工厂方法模式实质:不仅仅产品要抽象, 工厂也需要抽象。这样的好处就是更拥抱变化,比如现在需要创建一个Cat对象,就不需要像简单工厂模式去修改create()方法,只需新增一个Cat工厂类即可,遵循了开闭原则。

三、抽象工厂模式

工厂方法模式中,具体工厂A和B,两者除了都是抽象工厂的子类,没有任何其他的交集,是完全独立的两个工厂。

那抽象工厂模式中,具体工厂之间就能产生交际。

抽象工厂模式是这么定义的,提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。可以理解为将同一类的产品子类归为一类,让他们继承同一个抽象子类,把他们当做一个组。

比如我们新增一个Cat类,我们可以把猫和兔子分类成宠物类型,也可以把猫和老虎分类成猫科动物类型。

所以代码修改一下:

public class AbstractFactoryClient {
    public static void main(String[] args) {
        AnimalFactory factory = new PetFactory();
		factory.createPet().sayA();
		factory.createMaoke().sayB();
		
		factory = new MaokeFactory();
		factory.createPet().sayA();
		factory.createMaoke().sayB();
	}
	// 抽象工厂类
    public interface AnimalFactory {
        Pet createPet();
        Maoke createMaoke();
    }
    
    // 宠物分类抽象
    public interface Pet {
        void sayA();
    }
    
    // 猫科分类抽象
    public interface Maoke {
        void sayB();
    }
    
    // 宠物分类的兔子
    static class RabbitWithPet implements Pet {
    	@Override
        public void sayA() {
            System.out.println("我是宠物兔");
        }
    }

    // 宠物分类的猫
    static class CatWithPet implements Pet {
    	@Override
        public void sayA() {
            System.out.println("我是宠物猫");
        }
    }
    
    // 猫科分类的猫
    static class CatWithMaoke implements Maoke {
    	@Override
        public void sayB() {
            System.out.println("我能上树,所以我是猫科动物的老大");
        }
    }
    
    // 猫科分类的老虎
    static class TigerWithMaoke implements Maoke {
    	@Override
        public void sayB() {
            System.out.println("老大没教我怎么上树");
        }
    }
    
    // 具体工厂类(宠物)
    static class PetFactory implements AnimalFactory{
    	
    	@Override
        public Pet createPet() {
            return new RabbitWithPet();
        }

		@Override
        public Maoke createMaoke() {
            return new CatWithMaoke();
        }
    }

    // 具体工厂类(猫科)
    static class MaokeFactory implements AnimalFactory{
        
        @Override
        public Pet createPet() {
            return new CatWithPet();
        }

        @Override
        public Maoke createMaoke() {
            return new TigerWithMaoke();
        }
    }
}

在抽象工厂模式中,可以不需要知道产品是什么样的,只需要知道是用哪个工厂类就行了。也可以根据子类的共同特性,将它们设计在一起,组成一个相同类型组,就可以很方便的直接调用。但是相对的,产品族比较难以扩展,增加一个产品,就需要增加相应的接口和实现类。


写在最后

工厂模式关心的是最终创建的对象,而不关心创建的过程,这样做的优点是为创建对象提供统一的接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的,在此同时还能给系统带来更大的可扩展性和尽量少的修改量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/15315.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【社区图书馆】PyTorch高级机器学习实战 读书感想

《PyTorch高级机器学习实战》十大特点 1. 深入全面的内容覆盖&#xff1a; 本书的内容深入而全面&#xff0c;涵盖了深度学习中的多个领域&#xff0c;包括自然语言处理、计算机视觉、强化学习等&#xff0c;并介绍了各种不同的神经网络结构和优化算法。 2. 理论和实践并重&am…

php执行语句在MySQL批量插入大数据量的解决方案及计算程序执行时间(大数据量、MySQL语句优化)

MySQL里批量插入大数据的解决方案 前言一、PHP计算程序执行时间二、Mysql批量插入数据1.INSERT INTO 语句2.批量插入大数据2.1 使用循环$sql的方式2.2 循环(值1, 值2,....)的语句2.3测试过程出现的错误 三、实战PHPExcel批量导入大数据量优化 前言 近期在MySQL报表开发过程中&…

【微服务笔记22】微服务组件之Sentinel控制台的使用(Sentinel Dashboard)

这篇文章&#xff0c;主要介绍微服务组件之Sentinel控制台的使用&#xff08;Sentinel Dashboard&#xff09;。 目录 一、Sentinel控制台 1.1、下载Dashboard控制台 1.2、搭建测试工程 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;添加配置信息 &#…

R语言的基本数学运算

目录 一、对象命名原则 二、基本数学运算 2.1 四则运算 2.2 余数和整除 2.3 次方或平方根 2.4 绝对值 2.5 exp()与对数 2.6 科学符号e 2.7 圆周率与三角函数 2.8 四舍五入函数 2.9 近似函数 2.10 阶乘 三、R语言控制运算的优先级 四、无限大 五、非数字&#xf…

3.7 Linux shell脚本编程(分支语句、循环语句)

目录 分支语句&#xff08;对标C语言中的if&#xff09; 多路分支语句&#xff08;对标C语言中的swich case&#xff09; 分支语句&#xff08;对标C语言中的if&#xff09; 语法结构: if 表达式 then 命令表 fi 如果表达式为真, 则执行命令表中的命令; 否则退出if语句,…

Linxu下性能指标采集工具之nmon工具的使用

前言 近期在测试JefLogTail&#xff0c;由于JefLogTail使用的是轮询的方式来监听文件夹&#xff0c;所以对cpu的消耗可能会高一些&#xff0c;所以在测试的时候着重关注CPU,Linux下查看CPU信息一般采用top命令来实时观察&#xff0c;但是这种对于只是通过观察数据的变化来评估…

Anaconda,CUDA注意事项

2. 呜呜呜&#xff01;&#xff01;&#xff01;用别人的环境&#xff0c;如果他是非GPU版本的TF&#xff0c;你把非GPU版本的TF卸载后安装GPU版本的TF他也装不上。。。会默认给你装非GPU版本的TF&#xff01;&#xff01;&#xff01;大坑比&#xff01;&#xff01;&#xf…

streamlit (python构建web可视化框架)笔记

文章目录 一、安装使用streamlit二、streamlit使用1.展示和数据样式2.dataframe()生成交互表和table()方法生成静态表3.绘制折线图4.绘制地图5.一些组件slider()滑动条 checkbox()确认框 selectbox()选择器6.侧边栏7.布局分列8.多页 三、Steamlit可视化简单应用--冒泡排序可视化…

科学防雷接地和雷电防护方案

说到防雷&#xff0c;可能不少人首先会想到避雷针&#xff0c;而“避雷针”这一概念&#xff0c;很容易让大家对防雷的概念造成误解。 误解1: 避雷针是用来“避雷”的。 其实&#xff0c;避雷针的学名叫“接闪器”&#xff0c;不是用来“避开雷击”的&#xff0c;而是用来“迎…

传统机器学习(七)支持向量机(2)sklearn中的svm

传统机器学习(七)支持向量机(2)sklearn中的svm 2 sklearn中的svm 2.1 LinearSVC及SVC参数详解 2.1.1 SVC参数 class sklearn.svm.SVC(*,C1.0, kernelrbf, degree3, gammascale, coef00.0, shrinkingTrue, probabilityFalse, tol0.001, cache_size200, class_weightNone, ve…

为什么企业要做大规模敏捷?

背景 软件工程里一个重要的指标就是“可用的软件”&#xff0c;敏捷宣言里也同样告诉我们“工作的软件高于详尽的文档”&#xff0c;那“可用的软件”、“工作的软件”意味着什么呢&#xff1f;在我的理解里&#xff0c;可以经历用户 “千锤百炼”的软件就是一个“可用的软件”…

这些vue基本语法,你掌握了吗

文章目录 一、 vue 项目重点概念介绍1. 单页面应用程序2. 单文件组件3.数据驱动视图 二、 vue 基本结构1、template2、script3、style 三、 vue 常用指令介绍1、内容渲染指令&#xff08;1&#xff09;插值表达式 {{xxx}} —常用方式&#xff08;2&#xff09;v-text&#xff0…

912. 排序数组

1.题目&#xff1a; 2.我的代码&#xff1a; C语言&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* sortArray(int* nums, int numsSize, int* returnSize) {//希尔排序int gap numsSize;//多次预排while (gap > 1) {/…

Ansys Zemax | 如何模拟双折射偏振器件

这篇文章介绍了什么是双折射现象、如何在OpticStudio中模拟双折射 (birefringence)、如何模拟双晶体的双折射偏振器以及如何计算偏振器的消光比。&#xff08;联系我们获取文章附件&#xff09; 什么是双折射现象 一般的光学材料都是均匀的各向同性的&#xff0c;也就是说无论光…

STM32物联网实战开发(6)——PWM驱动LED灯

PWM驱动LED灯 之前是使用标准库函数配置引脚输出PWM控制呼吸灯&#xff0c;因为开发板上的蜂鸣器是有源的&#xff0c;所以这次还是用来确定LED灯&#xff0c;这次使用的是HAL库&#xff0c;用CubeMX软件初始化PWM功能 PWM输出原理 Period&#xff1a;周期&#xff0c;单位是秒…

语音处理加窗分帧

语音处理加窗分帧 一、分帧 语音数据和视频数据不同&#xff0c;本没有帧的概念&#xff0c;但是为了传输与存储&#xff0c;我们采集的音频数据都是一段一段 的。为了程序能够进行批量处理&#xff0c;会根据指定的长度(时间段或者采样数)进行分段&#xff0c;结构化为我们编程…

Javaweb | 转发、重定向

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 转发 转发与页面跳转 转发 转发的作用在服务器端&#xff0c;将请求发送给服务器上的其他资源&#xff0c;以共同完成一次请求的处理 页面跳转 使用forward跳转时&am…

拍卖小程序开发:从需求分析到设计实现

在当今数字时代&#xff0c;拍卖小程序已经成为了一个重要的销售和交易工具。拍卖小程序的开发不仅能够提供高效的销售渠道&#xff0c;还能够为用户提供全新的购物体验。因此&#xff0c;开发一个拍卖小程序成为了许多商家的首要任务。 拍卖小程序的开发可以帮助商家拓展销售…

Linux下实现共享内存的两种机制(附源码)

START Hello 大家好。 今天来讲一下Linux进程通信中重要的通信方式&#xff1a;共享内存作为Linux软件开发攻城狮&#xff0c;进程间通信是必须熟练掌握的重要技能&#xff0c;而共享内存是在程序开发中常用的也是重要的一种进程间通信方式。 下面我们就来聊一聊Linux下进程间…

pytest自动化框架之allure测试报告的用例描述设置

allure测试报告的用例描述相关方法&#xff1b;如下图 allure标记用例级别severity 在做自动化测试的过程中&#xff0c;测试用例越来越多的时候&#xff0c;如果执行一轮测试发现了几个测试不通过&#xff0c;我们也希望能快速统计出缺陷的等级。 pytest结合allure框架可以对…