面试笔记——工厂模式(简单工厂、工厂方法模式、抽象工厂模式)

2024-05-07 18:44

本文主要是介绍面试笔记——工厂模式(简单工厂、工厂方法模式、抽象工厂模式),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

场景需求:设计一个咖啡店点餐系统。 设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。

在不使用工厂模式情况下,类设计如下:
在这里插入图片描述
以上类图中的符号表示:

  • +:表示public
  • -:表示private
  • #:表示protected
  • 泛化关系(继承) 用带空心三角箭头的实线来表示
  • 实现关系 用带空心的三角箭头的虚线来表示
  • 依赖关系 使用带箭头的虚线来表示
  • 类图的分成三部分:第一部分——类的名称;第二部分——类的属性;第三部分——类的方法,方法的“:”后面表示方法的返回值类型

简单工厂模式

简单工厂包含如下角色:

  • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品 :实现或者继承抽象产品的子类,每种具体产品都有自己的特点。
  • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。

简单工厂模式下的类实现:
在这里插入图片描述
CoffeeStore不再关注创建咖啡的类型,创建咖啡的具体实现交给SimpleCoffeeFactory。

简单工厂模式的主要优点

  1. 封装性:客户端代码不需要知道创建对象的具体类,只需要知道相应的参数即可,这降低了客户端代码与具体实现之间的耦合度。

  2. 集中管理:所有的对象创建逻辑都集中在工厂类中,便于管理和维护。

  3. 易于扩展:当需要添加新的产品类型时,只需要在工厂类中添加新的逻辑,而不需要修改客户端代码。

简单工厂模式的缺点

  1. 违反开闭原则:当添加新的产品类型时,需要修改工厂类,这违反了开闭原则(软件工程原则之一,即软件实体应当是可扩展,而不可修改的)。

  2. 工厂类职责过重:随着产品类型的增多,工厂类的职责可能会变得过于繁重,这可能导致代码的可读性和可维护性下降。

  3. 类型安全问题:由于工厂方法通常使用字符串参数来确定要创建的对象类型,这可能导致类型安全问题,比如传入无效的参数。

工厂方法模式

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

工厂方法模式下类的具体设计:
在这里插入图片描述
Coffee类是抽象产品角色;AmericanCoffee和LatteCoffee类是具体产品角色;CoffeeFactory是抽象工厂角色,定义了创建产品的规范;AmericanCoffeeFactory和LatteCoffeeFactory是具体工厂角色。

此设计模式下的调用关系:
在这里插入图片描述
为了便于理解,CoffeeStore的代码如下:

public class CoffeeStore {public static void main(String[] args) {//可以根据不同的工厂,创建不同的产品CoffeeStore coffeeStore = new CoffeeStore(new LatteCoffeeFactory());Coffee latte = coffeeStore.orderCoffee();System.out.println(latte.getName());}private CoffeeFactory coffeeFactory;public CoffeeStore(CoffeeFactory coffeeFactory){this.coffeeFactory = coffeeFactory;}public Coffee orderCoffee(){Coffee coffee = coffeeFactory.createCoffee();//添加配料coffee.addMilk();coffee.addSuqar();return coffee;}
}

如上面的代码所示,用户只需要根据需求,创建一个具体工厂对象就可以了。

工厂方法模式的优点

  1. 解耦:用户只需要知道具体工厂的名称就可以得到所要的产品,无需知道产品的具体创建过程。
  2. 扩展性:当系统需要引入新的产品时,只需要添加新的具体产品类和对应的具体工厂类,无需修改原有的工厂类,这符合开闭原则
  3. 灵活性:工厂方法模式提供了一种灵活的方式来创建对象,解除了客户端与具体产品的依赖关系,增加了代码的可扩展性和可维护性。

工厂方法模式的缺点

  1. 增加系统复杂度:每增加一个产品,就需要增加一个具体产品类和对应的具体工厂类,这增加了系统的复杂度、开发量和维护成本。。
  2. 运行效率低:每次创建具体产品类的实例时,都需要通过具体工厂类来创建,这可能会影响系统的运行效率。

抽象工厂模式

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。

关于产品和等级的理解:
在这里插入图片描述
产品族:一个品牌下面的所有产品;例如华为下面的电脑、手机称为华为的产品族;
产品等级:多个品牌下面的同种产品;例如华为和小米都有手机电脑为一个产品等级;

工厂方法模式只考虑生产同等级的产品,抽象工厂可以处理多等级产品的生产。

使用场景:现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点

  • 同一个产品等级(产品分类)
    • 咖啡:拿铁咖啡、美式咖啡
    • 甜点:提拉米苏、抹茶慕斯
  • 同一个风味,就是同一个产品族(相当于同一个品牌)
    • 美式风味:美式咖啡、抹茶慕斯
    • 意大利风味:拿铁咖啡、提拉米苏

类的具体实现:
在这里插入图片描述
产品工厂就是超级工厂角色。
此时的调用关系为:
在这里插入图片描述
抽象工厂模式的优点

  1. 客户端无需知道它所需要的对象的类,只需要知道相应的工厂即可,这降低了客户端与具体实现之间的耦合度。
  2. 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  3. 当需要引入新的产品族时,只需要添加新的工厂类和对应的具体产品类,而无需修改已有的代码,这符合开闭原则。
  4. 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

抽象工厂模式的缺点

  1. 产品族扩展困难,需要修改工厂类的代码来支持新的产品族。

综上:

  • 简单工厂(并不算是设计模式)
    • 所有的产品都共有一个工厂,如果新增产品,则需要修改代码,违反开闭原则
    • 是一种编程习惯,可以借鉴这种编程思路
  • 工厂方法模式
    • 给每个产品都提供了一个工厂,让工厂专门负责对应的产品的生产,遵循开闭原则
    • 项目中用的最多
  • 抽象工厂方法模式
    • 如果有多个纬度的产品需要配合生产时,优先建议采用抽象工厂(工厂的工厂)
    • 一般的企业开发中的较少

这篇关于面试笔记——工厂模式(简单工厂、工厂方法模式、抽象工厂模式)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968080

相关文章

sort常用排序模式---------shell基础篇(三)

sort 排序命令使用 表达式意义sort -c test测试文件“test”是否已经经过排序,一般用处不大sort -k1 test.txt按照第1域对文件test.txt进行排序,日常可以用来对合并的日志文件进行时间排序sort -k1 -m log1.txt log2.txt按照第一域进行排序后合并输出到控制台,建议使用“>>” 将合并内容输出到另一个文件中sort -t / -k3 te

threejs坑记录-笔记

雪花 注意depthTest: false 否则会出现有transparent无效 const createSnow = () => {let map = new THREE.TextureLoader().load(snow);let material = new THREE.SpriteMaterial({map: map,transparent: true,side: THREE.Dou

listview在拖动的时候背景图片消失变成黑色背景的原因及解决方法

listview在拖动的时候背景图片消失变成黑色背景的原因是:当我们不拖动的时候确实是显示你自己定义的背景色,但是当我们拖动的时候就变黑了,这是为什么呢?   因为在没有设置下,listview的默认背景是和系统窗口一样的黑色,我们拖动的时候listview的默认颜色(我的是黑色)覆盖了你自己定义的背景色,所以才显示的是黑色,而不是你自己定义的颜色。我们只需要把listview的背景色改变或者透明

去除appcompat_v7(第二种方法的补充)

当我们创建新的Android项目移除 create Activity前的选项框,通过这样做,eclipse将不会自动引用这个库项目“appcompat_v7”。然后你可以手动地创建主活动。但是如果你有fragment和actionbar这些控件时注意一定要引用。  之前的方式请   点击这里 !!!

iOS 延迟执行的几种方法

1、performSelector方法 - (void)viewDidLoad {[super viewDidLoad];NSLog(@"当前时间:%@",[NSDate date]);[self performSelector:@selector(delayMenthod) withObject:nil afterDelay:2.0];}- (void)delayMenthod{NSLog(

dpkg: status database area is locked by another process 解决方法

解决办法:sudo rm -rf /var/lib/dpkg/lock 或者:rm -rf /var/lib/dpkg/lock

Vue学习笔记:拦截器

原文地址 Vue可以对http request和http response添加全局拦截,最典型的例子就是在请求头里添加token,和监测是否登录,如果没有登录则跳转到登录页面。 main.js中添加拦截器的代码: 1. request 拦截器 //request 拦截器,在请求头中加tokenaxios.interceptors.request.use(config => {if (lo

Java之责任链模式

一.前言 在公司一般的请假流程中,1天或者以下由组长批准,1-3天的由组长,经理审批,如果是3-7天的由组长,经理,部门领导审批,如果大于7天的则有上级批准。这种模式在设计模式里面的责任链模式可以得到很好的运用,下面用这个该模式实现体会一下责任链模式的好处。 二.定义 定义:将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能处理则处理

Android中切换到主线程更新方法

方法一: view.post(Runnable action) 在子线程中更新UI textView.post(new Runnable() {@Overridepublic void run() {textView.setText("更新textView");}}); 如果你的子线程里可以得到要更新的view的话,可以用此方法进行更新。 view还有一个方法view.postDel

Pytorch学习笔记_4_训练一个分类器

关于数据 一般来说,对于图像、文本、音频或视频数据,可以使用标准的Python包来将这些数据加载为numpy array,之后可以将这些array转换为torch.*Tensor 对于图像,Pillow、OpenCV包音频,scipy、librosa包文本,可以使用原始Python和Cython加载,或NLKT和SpaCy 特别的,对于视觉任务,有一个包torchvision,其中包含了处理