热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java23种设计模式之第三弹工厂模式

说起工厂,我们第一反应是制作什么东西的吧~。在现实生活中,工厂,就是用于生成一些特定事物的厂商。回到我们此处说的工厂模式上,




说起工厂,我们第一反应是制作什么东西的吧~。在现实生活中,工厂 , 就是用于生成一些特定事物的厂商。

回到我们此处说的工厂模式上,什么是工厂模式呢 , 顾名思义,就是生成我们的对象的类就会称成为工厂。
我们这里说的工厂模式 包括了三种工厂模式 : 分别是 简单工厂 、工厂方法、抽象工厂。


一、简单工厂

1、简单工厂定义:

简单工厂也称为静态工厂。是一种创建型模式。在简单工厂中,可以根据传入参数的不同返回不同类的对象实例。简单工厂是一个专门的工厂类,用来创建不同其他类的实例对象。这些实例对象通常他们的父类是同一个抽象类或者接口。


2、我们为什么要使用简单工厂呢?他可以带给我们什么好处呢?

在通常的做法中,我们会将对象创建的代码写在具体的业务代码中(即使用对象的代码写到一块)。这样会存在一个问题就是——>假设使用对象的地方有多个类使用,且创建对象的过程相似。在多个使用对象的类中都需要写一遍重复的构建对象的代码。

当我们不关心对象的产生方式时,我们就可以使用简单工厂模式。


3、我们可以先看下类图



普通类图
在这里插入图片描述




简单工厂类图
在这里插入图片描述
对于简单工厂来说。如果在版本迭代的过程中,产品类(Product)初始化的相关逻辑需要更改,我们只需要修改简单工厂类中的逻辑即可。不需要修改原有的业务逻辑类,也不会产生修改此业务逻辑造成原有类中其他部分出现问题。



4、代码示例



抽象产品。


package com.starcpdk.factory.simpleFactory;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/17 20:03
* @Version 1.0
*/

public abstract class Food {
String name;
public Food() {
}
public Food(String name) {
this.name = name;
}
public abstract void eat(String foodName);
public abstract void back(String foodName);
public abstract void cut(String foodName);
public abstract void paper(String foodName);
}


具体产品1


package com.starcpdk.factory.simpleFactory;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/17 20:07
* @Version 1.0
*/

public class Bread extends Food{
public Bread(String name) {
super(name);
}
public Bread() {
}
@Override
public void eat(String foodName) {
System.out.println(super.name + "吃" + foodName);
}
@Override
public void back(String foodName) {
System.out.println(super.name + "烤" + foodName);
}
@Override
public void cut(String foodName) {
System.out.println(super.name + "切" + foodName);
}
@Override
public void paper(String foodName) {
System.out.println(super.name + "准备" + foodName);
}
}


具体产品2


package com.starcpdk.factory.simpleFactory;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/17 20:07
* @Version 1.0
*/

public class Rice extends Food{
public Rice(String name) {
super(name);
}
public Rice() {
}
@Override
public void eat(String foodName) {
System.out.println(super.name + "吃" + foodName + "嘎嘎香");
}
@Override
public void back(String foodName) {
System.out.println(super.name + "烤"+ foodName + "嘎嘎旺");
}
@Override
public void cut(String foodName) {
System.out.println(super.name + "切" + foodName + "嘎嘎爽");
}
@Override
public void paper(String foodName) {
System.out.println(super.name + "准备"+ foodName +"嘎嘎愉快");
}
}


简单工厂


package com.starcpdk.factory.simpleFactory;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/17 20:03
* @Version 1.0
*/

public class SimpleFactory {
private SimpleFactory() {
}
private static Food food;
public static Food createFood(String foodType) {
if (foodType.equals("rice")) {
food = new Rice("张三");
} else if (foodType.equals("bread")) {
food = new Bread("李四");
}
return food;
}
}


客户端


package com.starcpdk.factory.simpleFactory;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/17 20:16
* @Version 1.0
*/

public class Main {
public static void main(String[] args) {
Food bread = SimpleFactory.createFood("bread");
bread.eat("法师面包");
Food rice = SimpleFactory.createFood("rice");
rice.eat("牛奶米饭");
}
}

5、使用场景

我们在不关注实例的创建过程时,就可以使用简单工厂模式。将类创建实例的过程交给工厂类去创建,我们只需需要去向工厂类索要实例即可。

主要是面向产品的创建,把创建由上层转移到下层。
如果项目的需求仅需new Product()能够满足后面的所有需求,依然使用最初的在业务层new 对象的方式即可。


二、工厂方法

简单工厂: 一个工厂统一负责所有产品的创建,一定会造成代码的可维护性差。相比简单工厂,工厂方法模式用一个工厂对应一类产品,创建的过程是一一对应的,也更加细颗粒度的创建,每当修改一个产品的创建过程,只需要修改产品对应的子类工厂即可。不会影响到其他产品的创建使用。将产品的创建过程延迟到工厂子类进行创建。

在这里插入图片描述



代码


package com.starcpdk.factory.factoryMethod;
public abstract class AbstractProduct {
public abstract void paper();
}

package com.starcpdk.factory.factoryMethod;
public class Product2 extends AbstractProduct{
@Override
public void paper() {
System.out.println("Product2 paper 。。。。");
}
}

package com.starcpdk.factory.factoryMethod;
public class Product1 extends AbstractProduct{
@Override
public void paper() {
System.out.println("Product1 paper 。。。。");
}
}

package com.starcpdk.factory.factoryMethod;
public abstract class AbstractFactory {
public abstract AbstractProduct createProduct();
}

package com.starcpdk.factory.factoryMethod;
public class Factory1 extends AbstractFactory{
@Override
public AbstractProduct createProduct() {
return new Product1();
}
}

package com.starcpdk.factory.factoryMethod;
public class Factory2 extends AbstractFactory{
@Override
public AbstractProduct createProduct() {
return new Product2();
}
}

package com.starcpdk.factory.factoryMethod;
public class Method {
public static void main(String[] args) {
AbstractFactory factory = new Factory1();
AbstractProduct product = factory.createProduct();
factory = new Factory2();
product = factory.createProduct();
product.paper();
product.paper();
}
}

总结:

相当于加了一层。在一个工厂类中生产各种产品,对单一产品的修改又或者增加产品都可能会影响到之前创建其他产品的逻辑。所以我们要加一层将创建产品的过程移至子类生产,每个工厂子类对应一个产品的生产。


  • 产品的增加和删除不会影响到其他产品的产出
  • 单个产品逻辑修改只需要在对应的工厂类修改即可,不需要动其他的工厂。
  • 职责更加明确,方便维护。

三、抽象工厂

抽象工厂是基于产品族的概念建立的。我们先想一下工厂方法模式 是 一个子类工厂对应一个子类产品。
而我们的抽象工厂相当于是 一个子类工厂对应 一些子类产品。 而这些子类产品是一类产品。比如说 我们有一个产品 他有两类描述 即形状 和 颜色。那我们可以将形状划分为一族产品 , 将颜色划分为另外一族产品。这样我们就是相当于有两个工厂类。一个去负责创建形状类产品,一个负责创建 颜色类产品。假如后期我们这个产品又增加了一族产品叫 味道,那我们只需要增加一个工厂去负责创建味道 类的产品即可。

但是形状 有长方形,正方形,圆形等。颜色有蓝色, 绿色,红色等。
这类里面会有很多的产品。抽象工厂相当于是针对一类一类划分出的工厂。而工厂方法则是针对一个一个产品划分工厂。

其实工厂方法模式是抽象工厂模式的一种特殊体。即抽象工厂中只有一个产品族时,就是我们的工厂方法模式。

假设我们有两族产品 : 现代风格。古代风格。
每族产品有两个:椅子、桌子。
那我们就有两个抽象产品 分别是椅子、桌子,然后我们有椅子对应的实际产品,桌子对应的实际产品去分别继承椅子和桌子。然后我们有一个抽象工厂。这个抽象工厂有两个方法,一个创建椅子,一个创建桌子,具体创建什么桌子或者什么椅子根据传入的参数决定。然后我们有两个具体工厂,分别是现代工厂、古代工厂。都去实现这个抽象工厂,也就是说这两个工厂都会产生桌子和椅子。具体产生什么样的桌子和什么样的椅子,由传入的参数决定。

在这里插入图片描述


代码

package com.starcpdk.factory.abstractfactory;
public abstract class ProductA {
}

package com.starcpdk.factory.abstractfactory;
public class ProductA1 extends ProductA {
}

package com.starcpdk.factory.abstractfactory;
public class ProductA2 extends ProductA {
}

package com.starcpdk.factory.abstractfactory;
public abstract class ProductB {
}

package com.starcpdk.factory.abstractfactory;
public class ProductB1 extends ProductB {
}

package com.starcpdk.factory.abstractfactory;
public class ProductB2 extends ProductB {
}

package com.starcpdk.factory.abstractfactory;
public abstract class AbstractFactory {
public abstract ProductA createProductA();
public abstract ProductB createProductB();
}

package com.starcpdk.factory.abstractfactory;
public class Factory1 extends AbstractFactory{
@Override
public ProductA createProductA() {
return new ProductA1();
}
@Override
public ProductB createProductB() {
return new ProductB1();
}
}

package com.starcpdk.factory.abstractfactory;
public class Factory2 extends AbstractFactory{
@Override
public ProductA createProductA() {
return new ProductA2();
}
@Override
public ProductB createProductB() {
return new ProductB2();
}
}

package com.starcpdk.factory.abstractfactory;
public class Client {
public static void main(String[] args) {
Factory1 factory1 = new Factory1();
System.out.println(factory1.createProductA());
System.out.println(factory1.createProductB());
Factory2 factory2 = new Factory2();
System.out.println(factory2.createProductA());
System.out.println(factory2.createProductB());
}
}

总结:抽象工厂是增加一类产品方便,但是在单个产品的增加上不方便。

抽象工厂相当于是 配套的生产,增加一套容易,但是给每套增加一个就不容易了。如果要增加一个产品。即在抽象工厂中需要增加一个方法,那么实现抽象工厂的具体工厂就全部需要增加该方法。但是如果是增加一族产品,那就比较容易了 ,只需要增加一个工厂,去实现抽象工厂,然后这个工厂就会实现抽象工厂中的方法去创建对应的产品,创建的还是一大类产品,这一大类产品中的产品个数是不变的。还是一套。







推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
author-avatar
zhenhuaYang
编程、骑行、健身、民谣、生活!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有