Effective C++中文版第三版 高清完整版PDF
有人说C++程序员可以分成两类,读过Effective C++的和没读过的。世界顶级C++大师Scott Meyers成名之作的第三版的确当得起这样的评价。当您读过这本书之后,就获得了迅速提升自己C++功力的一个契机。
在国际上﹐本书所引起的反响﹐波及整个计算技术出版领域﹐余音至今未绝。几乎在所有C+
文件:n459.com/file/25127180-477296466
以下内容无关:
-------------------------------------------分割线---------------------------------------------
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
所谓的“工厂”,就是用来将创建对象的代码封装起来,因为这部分代码将来变动的几率很大,所以这里的“工厂”的实质作用就是“封装变化”,以便于维护。
其中用到了“针对接口编程,而非针对实现编程”的设计原则。
下面通过一个销售饮料的例子,来对这三种工厂模式进行介绍。
1,简单工厂模式
假如现在有一位老板,想开一家饮料店,该店销售各种口味的饮料,比如苹果味,香蕉味,橙子味等。
将这些饮料用代码来表示,如下:
class Drink {
public void packing() {
//
}
}
class DrinkApple extends Drink {
}
class DrinkBanana extends Drink {
}
class DrinkOrange extends Drink {
}
Drink 类为所有其它味道的饮料的父类。
当有顾客来购买饮料的时候,顾客需要说明想买哪种口味的饮料,然后服务员就去将该口味的饮料取过来,包装好,然后交给顾客。
下面我们用最简单直接的代码,来模拟饮料店和卖饮料的过程,如下:
class DrinkStore {
public Drink sellDrink(String flavor) {Drink drink;if (flavor.equals("apple")) {drink = new DrinkApple();} else if (flavor.equals("banana")) {drink = new DrinkBanana();} else if (flavor.equals("orange")) {drink = new DrinkOrange();} else {drink = new Drink();}drink.packing();return drink;
}
}
但是这种实现方式有个问题,就是当需要下架旧饮料或上架新饮料的时候,会导致下面这部分代码被频繁的修改:
if (flavor.equals(“apple”)) {
drink = new DrinkApple();
} else if (flavor.equals(“banana”)) {
drink = new DrinkBanana();
} else if (flavor.equals(“orange”)) {
drink = new DrinkOrange();
} else {
drink = new Drink();
}
那这就违背了设计原则中的开闭原则:代码应该对扩展开发,对修改关闭。所以我们需要对该代码进行改进,那如何修改呢?
简单工厂模式告诉我们要将类似这样的代码封装到一个类里边,这个类就叫做简单工厂类,该类中提供一个方法,它可以生产我们所需要的各种对象。
下面用代码来模拟这个简单工厂类,如下:
class SimpleDrinkFactory {
public Drink createDrink(String flavor) {
Drink drink;
// 这段容易被频繁修改的代码,被封装到了工厂类中if (flavor.equals("apple")) {drink = new DrinkApple();} else if (flavor.equals("banana")) {drink = new DrinkBanana();} else if (flavor.equals("orange")) {drink = new DrinkOrange();} else {drink = new Drink();}return drink;
}
}
可以看到,createDrink 方法完成了创建 Drink 的任务。
createDrink 方法也可以定义成静态方法,优点是在使用 createDrink 方法时不需要再创建对象,缺点是不能再通过继承的方式来改变 createDrink 方法的行为。
下面来看如何使用 SimpleDrinkFactory 类:
class DrinkStore {
private SimpleDrinkFactory factory;
public DrinkStore(SimpleDrinkFactory factory) {this.factory = factory;
}public Drink sellDrink(String flavor) {Drink drink = factory.createDrink(flavor);drink.packing();return drink;
}
}
可以看到,我们将 SimpleDrinkFactory 类的对象作为 DrinkStore 类的一个属性,经过改进后的 sellDrink 方法就不需要再被频繁修改了。如果再需要上架下架饮料,则去修改简单工厂类 SimpleDrinkFactory 即可。
我将完整的简单工厂代码放在了这里,供大家参考,类图如下:
在这里插入图片描述
2,工厂方法模式
简单工厂模式从严格意义来说并不是一个设计模式,而更像一种编程习惯。
工厂方法模式定义了一个创建对象的接口(该接口是一个抽象方法,也叫做“工厂方法”),但由子类(实现抽象方法)决定要实例化的类是哪个。
在工厂方法模式中,父类并不关心子类的具体实现,但是父类给了子类一个“规范”,让子类必须“生成”父类想要的东西。
工厂方法将类的实例化推迟到了子类中,让子类来控制实例化的细节,也就是将创建对象的过程封装了起来。而真正使用实例的是父类,这样就将实例的“实现”从“使用”中解耦出来。因此,工厂方法模式比简单工厂模式更加有“弹性”。
下面我们来看下如何用工厂方法模式来改进上面的代码。
首先,定义 DrinkStoreAbstract,它是一个抽象父类:
abstract class DrinkStoreAbstract {
// final 防止子类覆盖
public final Drink sellDrink(String flavor) {Drink drink = factoryMethod(flavor); // 使用实例drink.packing();return drink;
}// 子类必须实现
protected abstract Drink factoryMethod(String flavor);
}
上面代码中 factoryMethod 方法就是所谓的工厂方法,它是一个抽象方法,子类必须实现该方法。
factoryMethod 方法负责生成对象,使用对象的是父类,而实际生成对象的则是子类。
接下来定义一个具体的 DrinkStore 类,它是 DrinkStoreAbstract 的子类:
class DrinkStore extends DrinkStoreAbstract {
@Override
public Drink factoryMethod(String flavor) {Drink drink;if (flavor.equals("apple")) {drink = new DrinkApple();} else if (flavor.equals("banana")) {drink = new DrinkBanana();} else if (flavor.equals("orange")) {drink = new DrinkOrange();} else {drink = new Drink();}return drink;
}
}
可以看到,子类中的 factoryMethod 方法有了具体的实现。
如果需要上架下架饮料,则去修改子类中的工厂方法 factoryMethod 即可。而 DrinkStoreAbstract 作为一个“框架”,无须改动。
完整的工厂方法代码放在了这里,供大家参考,类图如下:
在这里插入图片描述
图中的粉色区域是工厂方法模式的重点关注区。
3,依赖倒置原则
在介绍抽象工厂模式之前,我们先来看看什么是依赖倒置原则。
依赖倒置包含了依赖和倒置两个词。
我们先来看看“依赖”,“依赖”是指类与类之间的依赖关系。
在本文刚开始时的 sellDrink 方法是这么写的:
public Drink sellDrink(String flavor) {
Drink drink;
if (flavor.equals("apple")) {drink = new DrinkApple();} else if (flavor.equals("banana")) {drink = new DrinkBanana();} else if (flavor.equals("orange")) {drink = new DrinkOrange();} else {drink = new Drink();}drink.packing();return drink;
}
sellDrink 方法依赖了三个具体类,如果饮料的味道继续增加的话,那么 sellDrink 方法将依赖更多的具体类。
这会导致只要任意一个具体类发生改变,sellDrink 方法就不得不去改变,也就是类 A 需要改变(A 也是一个具体类)。
在这里插入图片描述
在上面这个关系图中,A 称为高层组件,各个具体类称为低层组件,所以在这幅图中,高层组件依赖了低层组件。
依赖倒置原则是指“要依赖抽象,而不依赖具体类”。更具体来说就是,高层组件不应该依赖低层组件,高层组件和低层组件都应该依赖抽象类。
那么怎样才能达到依赖倒置原则呢?工厂方法就可以!
在经过工厂方法模式的改造之后,最终的 DrinkStoreAbstract 类中的 sellDrink 方法变成了下面这样:
public final Drink sellDrink(String flavor) {
Drink drink = factoryMethod(flavor); // 使用实例drink.packing();return drink;
}
这使得 sellDrink 的所在类不再依赖于具体类,而依赖于一个抽象方法 factoryMethod,而 factoryMethod 方法依赖于 Drink,然后,各个具体类也依赖于 Drink,Drink 是一个广义上的“抽象接口”。
这样,高层组件和低层组件都依赖于 Drink 抽象,关系图变成了下面这样:
在这里插入图片描述
之前各个具体类的箭头是向下指的,而现在各个具体类的箭头是向上指的,箭头的方向倒了过来,这就是所谓的依赖倒置。
依赖倒置原则使得高层组件和低层组件都依赖于同一个抽象。
那怎样才能避免违反依赖倒置原则呢?有下面三个指导方针:
变量不要持有具体类的引用。
需要 new 对象的地方,要改为工厂方法。
类不要派生自具体类,而要从抽象类或接口派生。
派生自具体类,就会依赖具体类。
子类不要覆盖父类中已实现的方法。
父类中已实现的方法应该被所有子类共享,而不是覆盖。
当然事情没有绝对的,上面三个指导方针,是应该尽量做到,而不是必须做到。
4,抽象工厂模式
下面来介绍抽象工厂模式。
假如临近春节,饮料店老板为了更好的销售饮料,准备购买一批礼盒,来包装饮料。为了保证礼盒的质量,规定礼盒只能从特定的地方批发,比如北京,上海等。
那我们就定义一个接口,让所有的礼盒都派生自这个接口,如下:
interface DrinkBoxFactory {
String createBox();
}
class BeiJingBoxFactory implements DrinkBoxFactory {
@Override
public String createBox() {return "BeijingBox";
}
}
class ShangHaiBoxFactory implements DrinkBoxFactory {
@Override
public String createBox() {return "ShangHaiBox";
}
}
下面需要编写 Drink 类,我们让 Drink 类是一个抽象类,如下:
abstract class Drink {
String flavor;
protected abstract void packing();
}
需要注意的是,在抽象类 Drink 中有一个抽象方法 packing,Drink 将 packing 的具体实现交给每个派生类。Drink 类只规定派生类中需要实现一个 packing,但并不关心它的具体实现。
下面编写每种口味的饮料,如下:
class DrinkApple extends Drink {
DrinkBoxFactory boxFactory;
public DrinkApple(DrinkBoxFactory boxFactory) {this.boxFactory = boxFactory;this.flavor = "DrinkApple";
}@Override
public void packing() {System.out.println(flavor + boxFactory.createBox());
}
}
class DrinkBanana extends Drink {
DrinkBoxFactory boxFactory;
public DrinkBanana(DrinkBoxFactory boxFactory) {this.boxFactory = boxFactory;this.flavor = "DrinkBanana";
}@Override
public void packing() {System.out.println(flavor + boxFactory.createBox());
}
}
class DrinkOrange extends Drink {
DrinkBoxFactory boxFactory;
public DrinkOrange(DrinkBoxFactory boxFactory) {this.boxFactory = boxFactory;this.flavor = "DrinkOrange";
}@Override
public void packing() {System.out.println(flavor + boxFactory.createBox());
}
}
可以看到每种口味的饮料中都有一个 boxFactory 对象,在 packing 时,从 boxFactory 中获取礼盒。
注意 boxFactory 是一个接口类对象,而不是一个具体类对象,因此,boxFactory 的具体对象是由客户决定的。
然后,DrinkStoreAbstract 还是沿用工厂方法模式中的定义,如下:
abstract class DrinkStoreAbstract {
// final 防止子类覆盖
public final Drink sellDrink(String flavor) {Drink drink = factoryMethod(flavor); // 使用实例drink.packing();return drink;
}// 子类必须实现
protected abstract Drink factoryMethod(String flavor);
}
然后我们实现使用北京礼盒包装的Store 和使用上海礼盒包装的Store,如下:
class BeijingDrinkStore extends DrinkStoreAbstract {
@Override
protected Drink factoryMethod(String flavor) {Drink drink = null;DrinkBoxFactory factory = new BeiJingBoxFactory();if (flavor.equals("apple")) {drink = new DrinkApple(factory);} else if (flavor.equals("banana")) {drink = new DrinkBanana(factory);} else if (flavor.equals("orange")) {drink = new DrinkOrange(factory);} return drink;
}
}
class ShangHaiDrinkStore extends DrinkStoreAbstract {
@Override
protected Drink factoryMethod(String flavor) {Drink drink = null;DrinkBoxFactory factory = new ShangHaiBoxFactory();if (flavor.equals("apple")) {drink = new DrinkApple(factory);} else if (flavor.equals("banana")) {drink = new DrinkBanana(factory);} else if (flavor.equals("orange")) {drink = new DrinkOrange(factory);}return drink;
}
}
经过这么一些列的改动,我们到底做了些什么呢?事情的起因是老板需要一些礼盒来包装饮料,这就是需求增加了。
因此我们引入了一个抽象工厂,即 DrinkBoxFactory,这个接口是所有礼盒工厂的父类,它给了所有子类一个“规范”。
抽象工厂模式提供了一个接口,用于创建相关对象的家族。该模式旨在为客户提供一个抽象接口(本例中就是 DrinkBoxFactory 接口),从而去创建一些列相关的对象,而不需关心实际生产的具体产品是什么,这样做的好处是让客户从具体的产品中解耦。
最终,客户是这样使用 DrinkStoreAbstract 的,如下:
public class AbstractMethod {
public static void main(String[] args) {
DrinkStoreAbstract beiStore = new BeijingDrinkStore();
beiStore.sellDrink(“apple”);
beiStore.sellDrink(“banana”);
beiStore.sellDrink(“orange”);
DrinkStoreAbstract shangStore = new ShangHaiDrinkStore();shangStore.sellDrink("apple");shangStore.sellDrink("banana");shangStore.sellDrink("orange");
}
}
完整的抽象工厂模式代码放在了这里,供大家参考,类图如下:
在这里插入图片描述
从该图可以看出,抽象工厂模式比工厂方法模式更复杂了一些,另外仔细观察它们两个的类图,各自所关注的地方(粉红色区域)也是不一样的。
工厂方法与抽象工厂的相同点都是将对象的创建封装起来。不同点是:
工厂方法主要关注将类的实例化推迟到子类中。
抽象工厂主要关注创建一系列相关的产品家族。
5,总结
工厂模式使用到的设计原则有:
针对接口编程,而非针对实现编程。
开闭原则。
依赖倒置原则。
封装变化。
Effective C++中文版第三版 高清完整版PDF相关推荐
- Vim实用技巧高清完整版PDF中文
Vim实用技巧高清完整版PDF是一本中文版的参考教材,该书适合想要学习和掌握 Vim 工具的读者阅读,有一定 Vim 使用经验的程序员,也可以参考查阅以解决特定的问题. 欢迎大家下载阅读学习:http ...
- python自学教程 pdf-《Python编程从入门到精通》PDF高清完整版-PDF下载
作者: 叶维忠 出版年: 2018-11-1 页数: 429 装帧: 平装 ISBN: 9787115478801 内容简介 · · · · · · 本书循序渐进.由浅入深地详细讲解了Python语言 ...
- python编程入门教程下载-《Python编程从入门到精通》PDF高清完整版-PDF下载
作者: 叶维忠 出版年: 2018-11-1 页数: 429 装帧: 平装 ISBN: 9787115478801 内容简介 · · · · · · 本书循序渐进.由浅入深地详细讲解了Python语言 ...
- Python编程快速上手让繁琐工作自动化中文高清完整版PDF带书签
简介 如今,人们面临的大多数任务都可以通过编写计算机软件来完成.Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.通过Python编程,我们能够解决现实生活中的很多任务. 本书是一本 ...
- python数据挖掘 百度云,常用数据挖掘算法总结及Python实现高清完整版PDF_python数据挖掘,python数据分析常用算法...
常用数据挖掘算法总结及Python实现 高清完整版PDF 第一部分数据挖掘与机器学习数学基础 第一章机器学习的统计基础 1.1概率论 l概率论基本概念 样本空间 我们将随机实验E的一切可能基本结果组成 ...
- Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25
Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...
- python基础教程pdf刘浪_《Python基础教程(第3版)》 PDF高清完整版_初学者如何学习Python...
<Python基础教程(第3版)> PDF高清完整版 初学者如何学习Python 内容简介 本书包括Python程序设计的方方面面:首先从Python的安装开始,随后介绍了Python的基 ...
- ARM Cortex M0权威指南_PDF电子书下载 带书签目录 高清完整版 http://pan.baidu.com/s/1jGKQSwY MariaDB入门很简单_PDF电子书下载 带
ARM Cortex M0权威指南_PDF电子书下载 带书签目录 高清完整版 http://pan.baidu.com/s/1jGKQSwY MariaDB入门很简单_PDF电子书下载 带 ...
- 传智播客php拔高_传智播客第30期PHP基础班视频教程(高清完整版)
传智播客第30期PHP基础班视频教程(高清完整版)--更多资源,课程更新在 多智时代 duozhishidai.com 多智时代资源,简介: 教程目录 day1 1html介绍 2html标签基本形式 ...
最新文章
- 《JAVA与模式》之模板模式(转载)
- 网站优化助力网站在同行中更加出类拔萃
- 共用体和枚举,写写意思下
- 计算机网络日,《计算机网络原理》教学日历[汇编].pdf
- 「Apollo」百度Apollo感知模块(perception)红绿灯检测代码完整+详细解析
- C/C++ 通过初始化列表和构造函数内赋值初始化成员变量的区别
- 教育部官宣延期开学 这些教培机构在线捐课捐资
- 将您重定向的次数过多。_吃鸡:蹦蹦将迎来新皮肤?体验服全面加强,最高时速也不打滑...
- appium python很慢_appium+python自动化测试遇到的坑及处理方案
- Java实现俄罗斯方块小游戏。(附完整源代码)
- 常用的Unicode码表(汉字从A到Z、数字、英文)
- Shapley Values
- [USACO16DEC]Team Building团队建设
- JBoss、Geronimo及Tomcat比较分析
- 传统手绘建模与次世代建模技术与流程的区别,在未来游戏行业中作为建模人如何做出职业规划
- 基于java民航售票管理系统源码(java毕业设计)
- 720实训——智慧消防案例分析
- VB.net 图片刷新闪烁 解决方案
- vant4的showtoast非正常显示问题
- 邮票的制作(1.主要画笔工具2.钢笔工具)
热门文章
- 腾讯即将开源微信、QQ都在用的动画神器;Linux Mint与Mozilla达成合作;Apache Flink ML 2.0.0发布 | 开源日报
- Linux安装Skype
- 邮件的发送方式有哪几种?
- oracle 数据库truncate,Oracle中的truncate用法
- 冰箱“扩容”的战事,在今夏格外猛烈
- 志不强者智不达,言不信者行不果
- vso downloader怎么安装?安装步骤+视频下载方法【图】
- Python解析CANoe录制的asc文件
- 3D游戏动漫人物头部是怎样做出来的?
- 返回200却页面崩溃,post 为空 TTFB 10 分钟?