当前位置: 首页 > 编程日记 > 正文

编程模式 之美 -- 抽象工厂模式

文章目录

        • 1. 解决问题
        • 2. 应用场景
        • 3. 实现如下:
          • C++实现
          • C语言实现
        • 4. 缺点

1. 解决问题

在工厂方法模式中,我们卖衣服。此时我们为每一种衣服创建不同的工厂,帽子有一个工厂专门创建,裤子有一个工厂专门创建,T恤有一个工厂专门创建。这样的方式保证了代码设计的开闭原则(对扩展开发,对修改关闭),解决了简单工厂模式中暴露的问题。

但是又凸显了新的问题,假如现在优衣库这个大工厂 里面需要生产不同的种类的衣服,我们需要创建一堆工厂。同时香蕉共和国 这个另一个大工厂也需要生产不同种类的衣服,我们又需要创建一堆工厂。在这种情况下,代码会增加很多重复逻辑。

于是抽象工厂模式推出,将帽子封装为一个工厂, 支持生产优衣库的帽子和香蕉共和国的帽子。将裤子封装为另一个工厂,用来生产优衣库的裤子和香蕉共和国的裤子。

2. 应用场景

  • 对象之间存在关联,两个对象使用同一个工厂生产,降低程序复杂度,减少不必要的重复逻辑。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构
  • 对象数量比较庞大,维护多个工厂则程序的复杂度过高,由工厂方法模式变更为抽象工厂模式

3. 实现如下:

C++实现

实现功能:仍然是生产衣服,我们使用抽象工厂模式 将优衣库的帽子和香蕉共和国的帽子统一生产,将优衣库的裤子和香蕉共和国的裤子统一生产。

#include <iostream>using namespace std;class Hat{public:virtual void createHat(void) = 0;virtual ~Hat(){}
};/*优衣库的帽子*/
class kuHat: public Hat {public:kuHat(){cout << "kuHat::kuHat()" << endl;}virtual void createHat(void) {cout << "kuHat::createHat()" << endl;}~kuHat(){cout << "kuHat::delete()" << endl;}    
};/*香蕉共和国的帽子*/
class bananHat: public Hat{public:bananHat(){cout << "bananHat::bananHat()" << endl;}virtual void createHat(void) {cout << "bananHat::createHat()" << endl;}~bananHat(){cout << "bananHat::delete()" << endl;}      
};class Paths{public:virtual void createPaths(void) = 0;virtual ~Paths(){}    
};/*优衣库的裤子*/
class kuPaths: public Paths{public:kuPaths(){cout << "kuPaths::kuPaths()" << endl;}virtual void createPaths(void) {cout << "kuPaths::createPaths()" << endl;}~kuPaths(){cout << "kuPaths::delete()" << endl;}      
};/*香蕉共和国的裤子*/
class bananPaths: public Paths{public:bananPaths(){cout << "bananPaths::bananPaths()" << endl;}virtual void createPaths(void) {cout << "bananPaths::createPaths()" << endl;}~bananPaths(){cout << "bananPaths::delete()" << endl;}      
};/*抽象工厂类*/
class Factory {public:virtual Hat *createHat() = 0;virtual Paths *createPaths() = 0;
};/*优衣库的工厂,用来创建优衣库的衣服*/
class FactoryKu: public Factory{public:Hat *createHat(){return new kuHat();}Paths *createPaths(){return new kuPaths();}
};/*香蕉共和国的工厂,用来创建香蕉共和国的衣服*/
class FactoryBanan: public Factory {public:Hat *createHat(){return new bananHat();}Paths *createPaths() {return new bananPaths();}
};int main() {/*创建一个优衣库的工厂,进行优衣库的衣服的生产,包括裤子和帽子*/Factory *factory1 = new FactoryKu();Hat *kuhat = factory1 -> createHat();Paths *kupaths = factory1 -> createPaths();kuhat -> createHat();kupaths -> createPaths();if(factory1) {delete factory1;factory1 = NULL;}if(kuhat) {delete kuhat;kuhat = NULL;}if(kupaths) {delete kupaths;kupaths = NULL;}return 0;
}

编译运行如下

kuHat::kuHat()
kuPaths::kuPaths()
kuHat::createHat()
kuPaths::createPaths()
kuHat::delete()
kuPaths::delete()
C语言实现

实现功能:工厂商店分别 售卖白苹果、红苹果、白葡萄、红葡萄

/*C语言实现抽象工厂模式*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>enum {WHITE,RED};/*苹果基类*/
typedef struct _Apple {void (*print_apple)(void);
}Apple;/*葡萄基类*/
typedef struct _Grape {void (*print_grape)(void);
}Grape;void print_white_apple(void) 
{printf("I'am a white apple!\n");return;
}void print_red_apple(void)
{printf("I'am a red apple!\n");return;
}
void print_white_grape(void)
{printf("I'am a white grape!\n");return;
}
void print_red_grape(void)
{printf("I'am a red grape!\n");return;
}/*水果商店*/
typedef struct _FruitShop {Apple * (*sell_apple)(void);Grape * (*sell_grape)(void);
}FruitShop;Apple* sell_white_apple(void)
{Apple* tmp_apple = (Apple*)malloc(sizeof(Apple));assert(NULL != tmp_apple);tmp_apple->print_apple = print_white_apple;return tmp_apple;
}Apple* sell_red_apple(void)
{Apple* tmp_apple = (Apple*)malloc(sizeof(Apple));assert(NULL != tmp_apple);tmp_apple->print_apple = print_red_apple;return tmp_apple;
}Grape* sell_white_grape(void)
{Grape* tmp_grape = (Grape*)malloc(sizeof(Grape));assert(tmp_grape != NULL);tmp_grape->print_grape = print_white_grape;return tmp_grape;
}
Grape* sell_red_grape(void)
{Grape* tmp_grape = (Grape*)malloc(sizeof(Grape));assert(tmp_grape);tmp_grape->print_grape = print_red_grape;return tmp_grape;
}/*工厂商店,卖不同颜色的苹果和葡萄*/
FruitShop* create_fruit_shop(int color)
{FruitShop* fruitshop = (FruitShop*)malloc(sizeof(FruitShop));assert(fruitshop != NULL);if (color == WHITE) {fruitshop->sell_apple = sell_white_apple;fruitshop->sell_grape = sell_white_grape;}else if (color == RED) {fruitshop->sell_apple = sell_red_apple;fruitshop->sell_grape = sell_red_grape;}return fruitshop;
}int main()
{FruitShop* fruitshop = create_fruit_shop(RED);Apple *ap = fruitshop->sell_apple();Grape *gp = fruitshop->sell_grape();ap->print_apple();gp->print_grape();if (ap != NULL) {free(ap);}if (gp != NULL) {free(gp);}if (fruitshop != NULL) {free(fruitshop);}return 0;
}

输出如下:

I'am a red apple!
I'am a red grape!

4. 缺点

抽象工厂模式 的扩展有一定的“开闭原则”倾向性:

  1. 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。(按照如上C++代码,我们买衣服,当我们增加一种衣服:裙子的时候,只需要增加一个新的生产裙子的工厂就可以,不需要修改原的衣服种类的代码)
  2. 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。(当我们又增加了名创优品的种类时,我们之前所有的类包括:hat,Paths,还有对应的工厂类都需要修改 )

相关文章:

java map class_java – 将通用Class参数限制为实现Map的类

我正在尝试编写一个Map构建器.其中一个构造函数将允许客户端指定他们希望构建的Map类型public class MapBuilder {private Map map;/*** Create a Map builder* param mapType the type of Map to build. This type must support a default constructor* throws Exception*/pub…

双击进入物料数据的指定视图

SET PARAMETER ID MAT FIELD i_matnr-matnr.“物料号SET PARAMETER ID MXX FIELD K. 进入基本视图 "Table T132CALL TRANSACTION MM03 AND SKIP FIRST SCREEN. MXX 可以在后台查看&#xff1a; SPRO->后勤系统-一般->物料主档->设定物料主档->…

java中Integer装箱的注意

Integer inb 2;//自动装箱 Integer inc 2; System.out.println(inb inc );//输出true Integer biga 128; Integer bigb 128; System.out.println(biga bigb);//输出false上面的代码来自李刚老师的书&#xff0c;应该注意其中的细节.上面的输出与Integer的设计有关。1.系统…

rem自适应js

Rem自适应js---flexible.min.js 网上看到很多移动端适配的各种方法&#xff0c;由于原来工作中对rem的疏忽&#xff0c;所以决定重新学习rem~ 由于移动端特殊性&#xff0c;本文讲的是如何使用rem实现自适应&#xff0c;或叫rem响应式布局&#xff0c;通过使用一个脚本就可以re…

设计模式 之美 -- 建造者模式

文章目录1. 解决问题2. 应用场景3. 实现C语言实现C实现4. 缺点1. 解决问题 描述如下场景&#xff1a; 类的数据成员很多&#xff08;8个以上&#xff09;&#xff0c;当我们进行初始化的时候放在初始化列表中&#xff0c;影响类的可读性&#xff0c;同时校验初始化参数列表是…

dateformat java 并发_java.text.DateFormat 多线程并发问题

在日常开发中&#xff0c;java.text.DateFormat 应该算是使用频率比较高的一个工具类&#xff0c;经常会使用它 将 Date 对象转换成字符串日期&#xff0c;或者将字符串日期转化成 Date 对象。先来看一段眼熟的代码&#xff1a;类 DateUtils 的方法 formatForDay() 在多线程的情…

每天一个摆脱if-else工程师的技巧——优雅的参数校验

在日常的开发工作中,为了程序的健壮性,大部分方法都需要进行入参数据校验。最直接的当然是在相应方法内对数据进行手动校验,但是这样代码里就会有很多冗余繁琐的if-else。throw new IllegalArgumentException("用户姓名不能为空");throw new IllegalArgumentException("性别不能为空");throw new IllegalArgumentException("性别错误");

我下载的最新的linux ADT+eclipse中没有NDK

问题描述我下载的是 adt-bundle-linux-x86_64-20140702.zip 这个版本。我已经安装了CDT了&#xff0c;但是还是没有NDK可以设置&#xff0c;而且在project右键android tools下 没有Add Native Support这个选项求指教&#xff0c;谢谢&#xff01; 解决方案1你的Eclipse插件好…

Android中去掉标题的方法总结

方法一&#xff1a;也一般入门的时候经常使用的一种方法在setContentView()方法的前面插入代码&#xff1a; requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 package com.example.helloword;import android.os.Bundle; import android.app.Activity; import and…

ImportError: No localization support for language ‘eng’ in python

ImportError: No localization support for language ‘eng’ in python 遇到這一個問題&#xff0c;是因為有缺少檔案&#xff0c;我是因為使用 pyinstaller 去包裝執行檔&#xff0c;所以需要手動加入這一個設定值進 .spec 檔案裡&#xff1a; hiddenimports[mysql,mysql.con…

C++ 智能指针(unique_ptr / shared_ptr)代码实现

文章目录unique_ptr 智能指针的实现shared_ptr 智能指针的实现指针类型转换unique_ptr 智能指针的实现 一个对象只能被单个unique_ptr 所拥有。 #include <iostream>using namespace std;/*增加模板类型&#xff0c;保证智能指针的类型是由传入的类型决定的*/ template…

winform实现截图

这个截图模仿QQ截图&#xff0c;左键单击开始截图&#xff0c;鼠标移动出现方框确定截图尺寸&#xff0c;放开时为最终尺寸&#xff0c;双击鼠标弹出保存对话框进行保存。 还有一点就是&#xff0c;如果截图尺寸方框已经确定&#xff0c;移动鼠标到所选区域内时&#xff0c;鼠标…

java interface list_你了解注解内的@interface List么

Annotation, Multi-valued annotation, nested annotation, 多值注解, 嵌套注解今天在研究Spring MVC的Validation机制时(这里 | 还有这里)&#xff0c;简单看了下一些注解的源码&#xff0c;比如Min&#xff0c;发现以前从来没注意到的注解写法。看来基础知识有疏漏啊.../*** …

Struts 2的输入校验(一)

9 Struts 2的输入校验输入校验有两种&#xff1a;客户端和服务器端校验。客户端校验一般是通过JavaScript来完成&#xff0c;这种校验可减轻服务器压力。服务器校验主要通过服务器端编程的方式来完成。(1) 客户端校验客户端校验一般是通过JavaScript来完成&#xff0c;这种校验…

通过document.domain实现跨域访问

通过document.domain实现跨域访问&#xff1a;https://blog.csdn.net/nlznlz/article/details/79506655 前端跨域方法之document.domain和location.hash&#xff1a;https://blog.csdn.net/WEB_YH/article/details/79364565 转载于:https://www.cnblogs.com/bydzhangxiaowei/p/…

设计模式 之美 -- 原型模式

文章目录1. 解决问题2. 应用场景3. 实现方式C实现C语言实现4. 缺点5. 和其他三种创建模式的对比&#xff08;单例&#xff0c;工厂&#xff0c;建造者&#xff09;1. 解决问题 如果对象的创建成本较大&#xff0c;而同一个类的不同对象之间的差别不大&#xff08;大部分字段相…

Objective-C语法简记

开始学习iPhone开发了&#xff0c;虽然现在已经有了Swift&#xff0c;但我还是老老实实地学习Objective-C&#xff0c;鄙人入门的程序语言是C&#xff0c;后来学习了C#和Java&#xff0c;现在来学Objective-C&#xff0c;这篇只是一些很简略的笔记&#xff0c;不算是语法书。 代…

java编写最大公约数_Java编写最大公约数和最小公倍数

package javaapplication24;class NegativeIntegerException extends Exception{String message;public NegativeIntegerException(){message"方法的参数值不是正整数";}public String toString(){return message;}}class MaxCommonDivisor{public int getMaxCommonD…

肤色检测算法 - 基于不同颜色空间简单区域划分的皮肤检测算法

由于能力有限&#xff0c;算法层面的东西自己去创新的很少&#xff0c;很多都是从现有的论文中学习&#xff0c;然后实践的。 本文涉及的很多算法&#xff0c;在网络上也有不少同类型的文章&#xff0c;但是肯定的一点就是&#xff0c;很多都是不配代码的&#xff0c;或者所附带…

【算法学习】堆排序建立最大堆

本文代码均转自&#xff1a; 作者&#xff1a;早就戒了 来源&#xff1a;CSDN 原文&#xff1a;https://blog.csdn.net/qq_37169817/article/details/79777264 版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请附上博文链接&#xff01; 1 public class HeapSort { 2…

设计模式 之美 -- 代理模式

文章目录1. 解决问题2. 应用场景1. 业务系统的非功能性开发2. 代理模式在RPC、缓存中的应用3. 实现C实现C语言实现1. 解决问题 客户端和目标对象之间需要进行交互&#xff0c;此时客户端类和目标对象类相关操作之间的逻辑如果交合在一起&#xff0c;会导致客户端和目标对象模块…

java中注解的使用_java中注解的使用

使用过ssh框架的人一定也使用过注解&#xff0c;尤其是在spring框架中&#xff0c;注解可谓是spring容器和AOP编程的重要环节。注解就是用于修饰类、全局变量、方法、参数或局部变量的接口&#xff0c;java中规定&#xff0c;注解的使用不允许影响其修饰类的存在&#xff0c;也…

水题/poj 1852 Ants

1 /*2 PROBLEM:poj18523 AUTHER:Nicole4 MEMO:水题5 */6 #include<cstdio>7 using namespace std;8 int cmax(int a,int b){return a>b?a:b;}9 int cmin(int a,int b){return a<b?a:b;} 10 int main() 11 { 12 int cases; 13 scanf("%d…

素数、最大公约数、最下公倍数、质因数分解

2013-08-18 11:20:43 素数、最大公约数、最下公倍数、质因数分解都是与素数相关的&#xff0c;解决了素数的问题&#xff0c;其他的都可以此为基础求解。 小结&#xff1a; 求1到n之间的素数的基本方法是通过遍历2到sqrt(n)&#xff0c;判断每个数是否是素数来得到&#xff0c;…

Spring注解 开发

转载于:https://www.cnblogs.com/JBLi/p/10489541.html

读书:个人成长 -- 即兴演讲

与人交流时&#xff0c;有人发言语无伦次&#xff0c;舌头像打了结。 有人一开讲便滔滔不绝&#xff0c;却毫无重点。 也有人说话索然无味&#xff0c;没法让你投以关注。 如何在任何场合游刃有余地表达&#xff1f; 如何掌控此时此刻&#xff0c;用说话影响他人&#xff1f; …

php mysql环境搭配_centos6.7下搭配apache php mysql环境

安装过程安装apacheapache默认端口为80, 而nginx默认端口也是80, 所以安装apache前, 检查是否安装了nginx, 确保80端口没有被占用, 然后执行以下命令安装apacheyum install httpd httpd-devel启动apache服务/etc/init.d/httpd start或service httpd start停止apache服务/etc/in…

我们如此努力,也不过是个普通人

http://www.nowamagic.net/librarys/eight/posts/2500文 / 張君雅 南方日报曾刊登了一条新闻&#xff0c;大意是说有个女孩子以她的成绩考入北大清华没问题。但她从小参加各种社会活动&#xff0c;深受曾留学法国的母亲“生命的意义在于体验最多而不是最好”影响&#xff0c;决…

Citrix XenServer@cloudstack基本功能测试报告2

Cloudstack功能测试1、创建Zone、Pod、Clusters&#xff0c;添加hosts、Primary Storage、Secondary Storage步骤&#xff1a;1、 登录cloudstack控制板2、 选择基础架构&#xff0c;选择区域&#xff0c;点击查看全部&#xff0c;然后点击添加区域3、 选择基本区域类型4、 输入…

ABP中的Filter(下)

接着上面的一个部分来叙述&#xff0c;这一篇我们来重点看ABP中的AbpUowActionFilter、AbpExceptionFilter、AbpResultFilter这三个部分也是按照之前的思路来一个个介绍&#xff0c;当然这里面如果和前面的Interceptor有重复的部分&#xff0c;那么将会对两者进行一个对比并作出…