大白话抽象工厂模式(Abstract Factory Pattern)

实例分析

大白话工厂方法模式(Factory Method)一文中,我们讲解了日产4S店工厂规模的扩大,创建了针对不同车型的工厂,减少了工厂的工作内容,提高了效率。下面我们继续以4S店的故事讨论抽象工厂模式。
为了满足各个阶层的客户,日产公司推出了豪华系列品牌英菲尼迪,而且为了吸引客户购买,购车赠送行车记录仪,购买日产汽车赠送日产行车记录仪。购买英菲尼迪汽车赠送英菲尼迪行车记录仪。

通过上面的描述我们引出产品族和等级结构的定义。
产品族:即来自一个家族,比如英菲尼迪汽车和英菲尼迪行车记录仪都来自英菲尼迪家族,日产汽车和日产行车记录仪都来自日产家族。
等级结构:可以理解为相同的产品,比如英菲尼迪汽车和日产汽车处于同一个等级结构,英菲尼迪行车记录仪和日产行车记录仪处于同一个等级结构。

现在假设工厂分为日产工厂和英菲尼迪工厂,且汽车和行车记录仪都只有一种型号。日产工厂需要生产相同产品族的日产汽车和日产行车记录仪。英菲尼迪工厂需要生产相同产品族的英菲尼迪汽车和英菲尼迪行车记录仪。

通过对比,发现和工厂方法模式的区别为:
工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构

代码如下:
代码片段1 汽车父类

/**
 * 汽车的父类
 * @author coderzcr
 */
public abstract class Car {
    String name;
    void printCar(){
        System.out.println(name+"汽车已制造完成");
    }
}

代码片段2 日产汽车

/**
 * 日产汽车
 * @author coderzcr
 */
public class NissanCar extends Car {
    NissanCar(){
        this.name = "日产";
    }
}

代码片段3 英菲尼迪汽车

/**
 * 英菲尼迪汽车
 * @author coderzcr
 */
public class InfinitiCar extends Car {
    InfinitiCar(){
        this.name = "英菲尼迪";
    }
}

代码片段4 行车记录仪父类

/**
 * 行车记录仪父类
 * @author coderzcr
 */
public abstract class DVR {
    String name;
    void printDVR(){
        System.out.println(name+"行车记录仪已制造完成");
    }
}

代码片段5 日产行车记录仪

/**
 * 日产行车记录仪
 * @author coderzcr
 */
public class NissanDVR extends DVR{
    NissanDVR(){
        this.name = "日产";
    }
}

代码片段6 英菲尼迪行车记录仪

/**
 * 英菲尼迪行车记录仪
 * @author coderzcr
 */
public class InfinitiDVR extends DVR {
    InfinitiDVR(){
        this.name = "英菲尼迪";
    }

}

代码片段7 工厂父类

/**
 * 工厂父类
 * @author coderzcr
 */
public abstract class AbstractFactory {
    abstract Car getCar();
    abstract DVR getDVR();
}

代码片段8 日产工厂

/**
 * 日产工厂
 * @author coderzcr
 */
public class NissanFactory extends AbstractFactory {
    @Override
    Car getCar() {
        return new NissanCar();
    }

    @Override
    DVR getDVR() {
        return new NissanDVR();
    }
}

代码片段9 英菲尼迪工厂

/**
 * 英菲尼迪工厂
 * @author coderzcr
 */
public class InfinitiFactory extends AbstractFactory {
    @Override
    Car getCar() {
        return new InfinitiCar();
    }

    @Override
    DVR getDVR() {
        return new InfinitiDVR();
    }
}

图1 类图
实例分析类图

抽象工厂模式定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

抽象工厂模式结构

图2抽象工厂模式类图
实例分析类图

抽象工厂模式包含如下角色:

  • AbstractFactory:抽象工厂
  • ConcreteFactory:具体工厂
  • AbstractProduct:抽象产品
  • Product:具体产品

抽象工厂模式分析

优点分析
  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点分析
  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

参考文献

  1. 3. 抽象工厂模式(Abstract Factory) — Graphic Design Patterns
  2. 设计模式(三)抽象工厂模式 · 写最好的设计模式专栏 · 看云
抽象工厂模式Abstract Factory Pattern) 引入: 在前面介绍的两个创建型模式里面,我们解决的都是有关"new"的问题,用它们来避免显式指定类创建对象。我写的也非常简单易懂,相信看过的朋友们都应该对简单工厂模式、工厂方法模式的意图、所能解决的问题及适用情景有一定的了解了。但是若要达到灵活运用,什么时候用,怎样用合适还不是看一篇文章就能解决的问题。呵呵..这需要你对OO的理解程度,你的项目开发经验等等许多方面的积累。一起努力喔。。 好了,咱们言归正传,通过对这两个模式的了解,我们掌握一种思想,就是在创建一个对象时,需要把容易发生变化的地方给封装起来,来控制变化(哪里变化,封装哪里),以适应客户的变动,项目的扩展。但是,我们在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作,同时由于需求的变化,这“一系列相互依赖的对象”也要改变,如何应对这种变化呢?如何像简单工厂模式、工厂方法模式一样绕过常规的"new",然后提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?可能有人会说,你也可以将这些对象一个一个通过工厂方法模式来解决呀?但是,我们试想,既然是一系列相互依赖的对象,它们是有联系的,每个对象都这样解决,你又如何来保证他们的联系呢?举一个例子:Windows桌面主题,当你更换一个桌面主题的时候,系统的开始按钮、任务栏、菜单栏、工具栏等等都变了,而且是一起变的,他们的色调都还很一致,难道类似这样的问题,怎么来解决呢?它的天敌就是抽象工厂模式。 意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 参考者: 也就是该模式中的各个类或对象之间的关系: 抽象工厂(Abstract Factory) 声明生成一系列抽象产品的方法 具体工厂(Concrete Factory) 执行生成一系列抽象产品的方法,生成一系列具体的产品 抽象产品(Abstract Product) 为这一系列的某一种产品声明接口 具体产品(Product) 定义具体工厂生成的具体产品的对象,实现产品接口 客户(Client) 我们的应用程序客户端(不要理解成人),使用抽象产品和抽象工厂生成对象。 抽象工厂模式UML图 抽象工厂模式在生活中的实例 咱们继续拿怎么穿衣服来说明这个抽象工厂模式。 就拿你来说吧。工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。咱们假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在你的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用OO的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。 分析: 要好好去读上面那个实例,虽然有点绕嘴,其实只要用心去读,分清了抽象工厂模式的各个角色,对理解设计模式是非常重要的。理解头绪,然后接合简单工厂模式、工厂方法模式对工厂家族的了解,再加上抽象工厂模式的意图,头脑中差不多有一个雏型了吧。好了,咱们一起来分析一下。。 先把各个角色揪出来。 抽象工厂:虚拟的衣柜,它只是个概念而已。在项目中可能是一个接口或抽象类,定义规则,取出上衣,裤子。 具体工厂:具体的存在的衣柜,它用于存放某一种成套的衣服,换句话说,这种成套的衣服都是从这个衣柜中取出的。在项 目中继承于抽象工厂,实现抽象工厂中的方法,取出具体产品,某一件上衣,某一条裤子。 抽象产品:虚拟的衣服,也只是个概念。在项目中可能是多个接口或抽象类,定义规则,有什么特性,起什么作用。 具体产品:具体的实际存在的产品,它指的就是用于组装成某一套衣服的某一件上衣或裤子。它继承自某一个抽象产品。实 现抽象产品中制定的规则,特性。 它们之间怎么联系呢?客户在用的时候,依赖的又是什么呢? 客户在要的时候,首先要说出你要的什么系列的衣服,然后根据它的要求生成一个具体工厂的实例,剩下的工作就都是这个倒霉的具体工厂了,它会根据自己的实现生成一个上衣,生成一个裤子,然后把它交给客户。客户在这一过程中并不知道具体工厂都做了什么。也就是说,客户只依赖于抽象工厂和抽象产品了。在初始化的时候会用到一次具体工厂类名,我们根据.NET特有的反射机制又可以把这个在客户端唯一的具体的非抽象类放到一个应用程序配置文件中,防止它变化。 这就符合了设计模式中的“开放--封闭”原则,依赖倒转原则,里氏代换原则等等。 具体代码如下: 抽象工厂角色: 1namespace AbstractFactory 2{ 3 //抽象工厂类, 4 public abstract class AbstractClothes 5 { 6 //抽象方法:创建一个上衣 7 abstract public AbstractCoat CreateCoat(); 8 //抽象方法:创建一个裤子 9 abstract public AbstractTrousers CreateTrousers(); 10 } 11} 12 抽象产品角色: 1namespace AbstractFactory 2{ 3 /**//// 4 /// 抽象产品----上衣抽象类 5 /// 6 public abstract class AbstractCoat 7 { 8 //性别属性 9 public abstract bool Sex 10 { 11 get; 12 } 13 14 //样式属性 15 public abstract string Style 16 { 17 get; 18 } 19 } 20 21 /**//// 22 /// 抽象产品----裤子抽象类 23 /// 24 public abstract class AbstractTrousers 25 { 26 //性别属性 27 public abstract bool Sex 28 { 29 get; 30 } 31 32 //样式属性 33 public abstract string Style 34 { 35 get; 36 } 37 } 38} 39 具体工厂角色: 1namespace AbstractFactory 2{ 3 /**//// 4 ///时尚男装 5 /// 6 public class FashionManClothes:AbstractClothes 7 { 8 public override AbstractFactory.AbstractCoat CreateCoat() 9 { 10 return new CoatA(); 11 } 12 13 public override AbstractTrousers CreateTrousers() 14 { 15 return new TrousersA(); 16 } 17 } 18 19 /**//// 20 /// 时尚女装 21 /// 22 public class FashionWomanClothes : AbstractClothes 23 { 24 public override AbstractCoat CreateCoat() 25 { 26 return new CoatB(); 27 //throw new Exception("The method or operation is not implemented."); 28 } 29 public override AbstractTrousers CreateTrousers() 30 { 31 return new TrousersB(); 32 //throw new Exception("The method or operation is not implemented."); 33 } 34 } 35} 具体产品角色:(注意:我并没有把所有的具体产品类都列出来,由于简单,可以推想出剩余的产品类,详见附件) 1namespace AbstractFactory 2{ 3 /**//// 4 /// 时尚男性上衣 5 /// 6 public class CoatA:AbstractFactory.AbstractCoat 7 { 8 private bool sex = true; 9 private string style = "时尚"; 10 /**//// 11 /// 重写基类的Sex属性 12 /// 13 public override bool Sex 14 { 15 get 16 { 17 return sex; 18 } 19 } 20 21 /**//// 22 /// 重写基类的Style属性 23 /// 24 public override string Style 25 { 26 get 27 { 28 return style; 29 } 30 } 31 } 32 33 /**//// 34 /// 时尚男性裤子 35 /// 36 public class TrousersA : AbstractTrousers 37 { 38 private bool sex = true; 39 private string style = "时尚"; 40 public override bool Sex 41 { 42 get 43 { 44 return sex; 45 } 46 } 47 public override string Style 48 { 49 get 50 { 51 return style; 52 } 53 } 54 } 55} 客户端代码: 1namespace AbstractFactory 2{ 3 /**//// 4 /// 创建衣服类 5 /// 6 public class CreateClothes 7 { 8 private AbstractCoat myCoat; 9 private AbstractTrousers myTrousers; 10 public CreateClothes(AbstractClothes clothes) 11 { 12 myCoat = clothes.CreateCoat(); 13 myTrousers = clothes.CreateTrousers(); 14 } 15 16 public void ShowMyClothes() 17 { 18 Console.WriteLine("My Clothes:"); 19 string sex= myCoat.Sex ? "男" : "女"; 20 //Console.WriteLine("Coat:{0} {1}", myCoat.Sex ? "男" : "女", myCoat.Style); 21 Console.WriteLine("Coat:{0} {1}", sex, myCoat.Style); 22 sex=myTrousers.Sex?"男":"女"; 23 Console.WriteLine("Trousers:{0} {1}", sex, myTrousers.Style); 24 } 25 } 26 27 28 public class Client 29 { 30 static void Main(string[] args) 31 { 32 //创建一个工厂类的实例 33 string assemblyName = ConfigurationManager.AppSettings["assemblyName"]; 34 string fullTypeName =string.Concat( ConfigurationManager.AppSettings["nameSpaceName"] ,".", ConfigurationManager.AppSettings["typename"]); 35 36 AbstractClothes factory = (AbstractClothes)Assembly.Load(assemblyName).CreateInstance(fullTypeName); 37 CreateClothes clothes = new CreateClothes(factory); 38 clothes.ShowMyClothes(); 39 Console.Read(); 40 } 41 } 42} 43 app.config文件 1 2 3 4 5 6 7 8
内容概要:本文系统介绍了物理信息神经网络(PINNs)在求解布洛赫-托雷(Bloch-Torrey)方程中的应用,结合PyTorch框架提供了完整的Python代码实现案例。文章深入阐述了如何将物理先验知识嵌入神经网络训练过程,通过构建复合损失函数,强制网络输出满足控制方程、初始条件与边界条件,从而实现对布洛赫-托雷方程的无网格化、高精度求解。该方法突破了传统数值方法在高维、多尺度及复杂几何场景下的计算瓶颈,展现出优异的泛化能力与计算效率,特别适用于医学成像、扩散磁共振等领域中复杂的物理场建模与仿真任务。; 适合人群:具备深度学习与偏微分方程理论基础,从事科学计算、生物医学工程、材料科学或相关交叉学科研究的研究生、科研人员及算法工程师。; 使用场景及目标:①应用于扩散磁共振成像(dMRI)等医学影像技术中的复杂扩散过程建模与反演;②为高维偏微分方程的高效求解提供数据驱动的新范式,提升仿真精度与计算速度;③作为PINNs在AI for Science领域中的典型实践案例,推动物理引导的深度学习方法在实际科研项目中的落地与拓展。; 阅读建议:建议读者结合提供的完整代码资源(可通过公众号“荔枝科研社”或百度网盘获取),动手复现并调试模型,深入理解PINNs的架构设计、损失函数构建与物理约束嵌入机制,同时可尝试将该方法迁移至其他类似物理系统的建模与求解任务中进行创新性研究。
内容概要:本文围绕“基于多VSG独立微网的多目标二次控制MATLAB模型研究”展开,详细阐述了利用Simulink对多虚拟同步发电机(VSG)构成的独立微网系统进行建模与仿真,实现频率调节、电压支撑与有功无功功率均分等多目标协同优化的二次控制策略。研究引入先进的最优控制算法,解决微网在孤岛运行模式下的功率动态分配、频率电压恢复及系统稳定性问题,并通过MATLAB/Simulink平台构建完整仿真模型,验证所提控制策略在不同负载扰动下的有效性、鲁棒性与动态响应性能。; 适合人群:具备电力系统分析、现代控制理论基础以及MATLAB/Simulink仿真能力的电气工程、自动化等相关专业的硕士研究生、科研人员及从事微网控制系统开发的工程技术人才。; 使用场景及目标:① 深入理解多VSG在独立微网中的并联运行机理与协同控制架构;② 掌握基于Simulink的微网二次控制系统的建模方法与仿真流程;③ 实现频率、电压与功率分配的多目标优化控制仿真验证;④ 为微网控制系统的设计、算法优化及科研课题提供可靠的仿真依据和技术参考。; 阅读建议:建议读者结合文中控制策略,动手搭建Simulink模型,重点关注控制器参数整定对系统动态性能的影响,可通过对比不同工况下的仿真结果,进一步优化控制算法以提升系统鲁棒性与响应精度。
【重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
代码下载地址: https://pan.quark.cn/s/a4b39357ea24 编写程序,建立容量为n(建议n=8)的循环队列,完成以下程序功能。 输入字符#,执行一次出队操作,屏幕上显示出队字符;输入字符@,队列中所有字符依次出队并按出队次序在屏幕上显示各字符;输入其它字符,则输入的字符入队。 要求采用队头/队尾间隔至少一个空闲元素的方法来实现循环队列;空队执行出队操作及队满执行入队操作需显示提示信息。 ### 数据结构实验报告知识点 #### 实验背景与目标 本次实验是关于数据结构中的队列基本操作算法。 队列是一种先进先出(FIFO)的数据结构,在计算机科学中有着广泛的应用,例如进程调度、任务队列等场景。 通过本实验,学生能够深入理解循环队列的概念,并熟练掌握其实现方法。 #### 实验要求与内容 1. **实验内容**:要求编写一个程序来建立容量为 _n_ 的循环队列(推荐 _n_ = 8),并实现以下功能: - 输入字符 `#` 执行一次出队操作,并显示该出队字符; - 输入字符 `@`,将队列中的所有字符依次出队,并按照出队顺序在屏幕上显示这些字符; - 输入其他任意字符,则将该字符入队。 2. **特殊要求**: - 采用队头/队尾间隔至少一个空闲元素的方法实现循环队列,这样可以避免队列的物理连续性与逻辑连续性的混淆,同时便于检测队列是否为空或满。 - 当队列为满时尝试执行入队操作,或者队列为时空执行出队操作时,需要给出相应的提示信息。 3. **注意事项**: - 在反复输入字符时,应妥善处理输入缓冲区中的回车键(即 `\n` 字符)的问题,避免因连续输入导致的错误行为。 #### 数据结构设计 为了实现上述要求,本实验采用了如下的数据结构设计: ...
内容概要:本文提出了一种基于数据驱动的Koopman算子与递归神经网络(RNN)相结合的模型线性化方法,用于提升纳米定位系统的预测控制性能。该方法通过Koopman算子将复杂的非线性系统动态映射至高维线性空间,克服传统建模在强非线性条件下的局限性,再结合RNN强大的时序特征捕捉能力,实现对系统未来状态的高精度预测与有效控制。整个框架完全基于数据驱动,无需精确物理建模,特别适用于原子力显微镜、半导体制造等对定位精度要求极高的应用场景,并通过Matlab代码实现了算法的完整仿真与验证。; 适合人群:具备控制理论基础和Matlab编程能力,从事精密运动控制、智能算法开发、非线性系统建模与预测控制研究的研究生、科研人员及工程技术开发者。; 使用场景及目标:①解决纳米级定位平台中存在的强非线性、迟滞、蠕变等复杂动态特性带来的控制难题;②为高精度机电系统提供一种可复现、易实现的数据驱动预测控制方案;③推动Koopman理论与深度学习在先进制造与智能控制领域的深度融合与应用创新。; 阅读建议:建议读者结合提供的Matlab代码深入理解Koopman算子的数值实现流程与RNN网络结构设计细节,重点关注模型在不同工况下的泛化能力、实时性表现及控制稳定性,可进一步将其拓展至其他高精度伺服控制系统的研究与优化中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值