设计模式讲义
- 格式:doc
- 大小:16.96 MB
- 文档页数:102
设计模式简单理解-概述说明以及解释1.引言1.1 概述设计模式是软件开发中常用的一种设计思想,通过将经常遇到的问题和解决方案抽象成模式,并给出通用的解决方案,以便于开发人员在项目中复用。
设计模式能够提供一种经过验证的解决方案,可以帮助开发人员更加快速地解决问题和提高代码质量。
设计模式的使用可以使软件系统更加灵活、易于维护和扩展,帮助开发人员编写出高质量的代码。
在本文中,我们将介绍设计模式的基本概念和常见类型,帮助读者理解设计模式的重要性和应用场景。
1.2 文章结构:本文将围绕设计模式展开讨论,主要分为引言、正文和结论三个部分。
在引言部分,将对设计模式进行概述,介绍文章的结构和目的。
在正文部分,将详细介绍设计模式的概念及其常见类型,以及设计模式的优势和应用场景。
最后,在结论部分,将总结设计模式的重要性,并给出应用设计模式的建议,同时展望设计模式在未来的发展前景。
通过本文的阐述,读者将能够对设计模式有一个简单的理解,并了解其在实际开发中的应用意义。
1.3 目的设计模式作为软件开发领域的重要内容,其目的主要有以下几点:- 提高代码的可读性和可维护性:设计模式提供了一种通用的解决方案,使得代码结构更清晰、更易于理解,并且易于维护和修改。
- 降低软件开发成本:设计模式可以帮助开发人员更快速地完成软件的开发工作,避免重复造轮子,提高代码重用性。
- 提高软件的可靠性和稳定性:设计模式经过反复的实践和验证,是一种被广泛认可的解决方案,使用设计模式可以减少软件错误并提高软件的稳定性。
- 促进团队协作和沟通:设计模式提供了一种通用的设计语言,使得团队成员之间更容易进行沟通和合作,在团队开发中发挥重要作用。
综上所述,设计模式的目的是为了提高软件的质量和效率,实现更好的软件开发过程和结果。
通过学习和应用设计模式,可以帮助开发人员更好地理解和应用软件开发的基本原则和方法,提高自身的软件设计和开发能力。
2.正文2.1 什么是设计模式设计模式是在软件开发中反复出现的问题的解决方案。
设计模式李建忠祝成科技高级培训讲师lijianzhong@面向对象的两个方向性思维底层思维抽象思维¾向下,如何深入把握机器底层,从微观理解对象构造——底层思维•语言构造•编译转换•对象内存模型•运行时机制•…… ¾向上,如何将我们的周围世界抽象为程序代码——抽象思维•面向对象•组件封装•设计模式•架构模式•……深入理解面向对象¾向下:深入理解三大面向对象机制¾封装,隐藏内部实现¾继承,复用现有代码¾多态,改写对象行为¾向上:深刻把握面向对象机制所带来的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计”软件设计固有的复杂性建筑商从来不会去想给一栋已建好的100层高的楼房底下再新修一个小地下室——这样做花费极大而且注定要失败。
然而令人惊奇的是,软件系统的用户在要求作出类似改变时却不会仔细考虑,而且他们认为这只是需要简单编程的事。
——Object-Oriented Analysisand Design with Applications Grady Booch复杂性的几个诱因¾问题领域的复杂性¾客户需求本身就很复杂,客户与开发人员互相不理解¾管理开发过程的困难¾开发是由人完成的,人的组织、潜能存在巨大复杂性¾软件可能的灵活性¾软件为开发人员提供了极大的灵活性,而开发人员也很容易滥用这种灵活性¾表征离散系统行为的困难¾软件系统本质上是一个离散系统,其复杂度要远远大于连续系统。
一个简单的外部事件可能破坏整个系统软件设计复杂的根本原因软件设计复杂性的根本原因在于:变化¾客户需求的变化¾技术平台的变化¾开发团队的变化¾市场环境的变化¾……如何解决复杂性?¾分解¾人们面对复杂性有一个常见的做法:即分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。
设计模式讲解设计模式是一种被广泛应用于软件开发中的概念,它是一种解决特定问题的经验总结,是一种被证明有效的解决方案。
设计模式可以帮助开发人员更好地组织代码,提高代码的可读性和可维护性,从而提高软件开发的效率和质量。
设计模式的分类设计模式可以分为三类:创建型模式、结构型模式和行为型模式。
1. 创建型模式创建型模式主要用于对象的创建,它们可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
创建型模式包括以下几种:1.1 工厂模式工厂模式是一种创建型模式,它提供了一种创建对象的方式,而不需要直接使用 new 关键字来创建对象。
工厂模式可以根据不同的参数来创建不同的对象,从而实现代码的灵活性和可扩展性。
1.2 抽象工厂模式抽象工厂模式是一种创建型模式,它提供了一种创建一系列相关或相互依赖对象的方式,而不需要指定它们的具体类。
抽象工厂模式可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
1.3 单例模式单例模式是一种创建型模式,它保证一个类只有一个实例,并提供了一个全局访问点。
单例模式可以帮助我们更好地管理全局状态,从而提高代码的可读性和可维护性。
2. 结构型模式结构型模式主要用于对象的组合,它们可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
结构型模式包括以下几种:2.1 适配器模式适配器模式是一种结构型模式,它可以将一个类的接口转换成客户端所期望的另一个接口。
适配器模式可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
2.2 装饰器模式装饰器模式是一种结构型模式,它可以动态地给一个对象添加一些额外的职责,而不需要修改它的代码。
装饰器模式可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
2.3 代理模式代理模式是一种结构型模式,它可以为一个对象提供一个代理,以控制对这个对象的访问。
代理模式可以帮助我们更好地管理对象的访问,从而提高代码的可读性和可维护性。
3. 行为型模式行为型模式主要用于对象之间的通信,它们可以帮助我们更好地组织代码,提高代码的可读性和可维护性。
黑马程序员设计模式之装饰者与工厂方法内容简介设计模式(Design pattern)代表了最佳的实践,是软件开发人员在软件开发过程中面临一般问题的解决方案,是优秀程序猿的经验结晶. 本次课程我们重点介绍设计模式中装饰者和工厂方法.装饰者设计模式动态给一个对象增加额外功能;若要扩展对象的功能,装饰者提供了比继承更具有弹性的方案.工厂方法设计模式精髓在于封装类中不变的部分,提取其中个性化善变的部分为独立类,降低程序的耦合度,提高了程序扩展性.知识点●面对对象编程原则之少用继承多用组合●面向对象编程原则之面向接口编程●设计模式之装饰者●简单工厂●面向对象编程原则之封装变化●设计模式之工厂方法第一章:设计模式之装饰者欢迎来到喜茶店喜茶店只供应两种饮料茗茶和咖啡,他们最初系统是这样的}为了吸引顾客,喜茶店提供了两种配料:芝士(Cheese),火腿(Ham),可以组合搭配每一种饮料. 通过继承来实现吗? 我们试试看,来看类图。
这只有两种饮料,两种配料就产生这么多类,每增加一种饮料或配料,类就呈几何级增长. 有的哥们会说这么烂的设计,干嘛不使用组合呢? 我们接下来组合一下.面向对象原则:少用继承,多用组合继承是是一个(is a) 关系,而组合是有一个(has a) 关系,也就是一个类中有另外一个类的引用. 为什么要少用继承,多用组合呢?1.继承可能会导致类的无限膨胀.2.继承关系是一种耦合度非常高的关系,因为一旦父类行为发生变化,子类也将受到影响。
3.而组合关系耦合度就没有那么高,尤其在组合“接口”时候,程序会变得更加灵活.注意: 我在这里讲的接口都是指的抽象类或接口.使用组合实现需求public class Cheese {public String desc(){return"芝士";}public double cost(){return 2.5;}}public class Ham {// 来一份双芝士的咖啡. 本店不提供!!!}}出现无法实现双份芝士的需求,并且如果增加一种配料必须修改原有的类,饮料类严重依赖具体配料类.面向对象原则:面向接口编程面向接口编程: 不要针对具体的类,而要针对接口; 因为具体的类总是善变的,而抽象的接口是相对稳定的.认识装饰者模式我们现在了解直接使用继承会产生类爆炸,直接组合也无法实现双份芝士的需求,并且让每一种饮料对配料都特别的依赖.我们来换一种思路,我们可不可以使用配料对饮料进行装饰(decorate)呢? 比如: 顾客要一份芝士火腿茗茶.1.创建一个茶(Tea)对象2.使用火腿(Ham)对它装饰3.使用芝士(Cheese)对它装饰那么如何计算最终价格,我们可以一层一层的加上去. 来看图装饰者模式的特点●装饰者与被装饰者要有相同的超类●你可以使用一个或多个装饰者装饰一个对象●由于装饰者和被装饰者相同的超类,所以在使用被装饰者的地方都可以使用装饰者替代●装饰者可以在调用被装饰者的方法之前或之后加上自己行为,已达到特定的目的.●你可以在运行时,不限量使用你喜欢的装饰者来装饰对象装饰者模式的定义装饰者模式: 动态给对象增加功能,若要扩展功能,装饰者提供了比继承更有弹性的方案.我们现在知道了装饰者模式的特点和定义,怎么把装饰应用起来呢? 我们来看装饰者类图接下来装饰我们的饮料.接下来我们来使用装饰者完成我们代码.◆从Beverage(饮料)开始,Beverage是一个接口不用动.}装饰者在实际开发中的应用装饰者在实际开发中有很多的应用场景,比如IO流中应用,Web中解决程序的乱码问题等. 我们接下看一下,IO流中是如何使用装饰者模式的呢?. 来看类图我们接下给InputStream增加一个装饰者,用于把读取数据中的大写转换为小写. 比如:data.txt中内容为“I Love Java,I Love HeiMa.”转换后为“i love java, i love heima.”代码实现public class LowercastInputStream extends FilterInputStream {protected LowercastInputStream(InputStream in) { super(in);}@Overridepublic int read() throws IOException {int ch = super.read();// 如果是大写,就转换为小写if(ch >= 'A' && ch <= 'Z'){ch = Character.toLowerCase(ch);}return ch;装饰者的缺陷①可能会产生大量的小类,增加了系统复杂性.②采用装饰这模式的时候,实例化“组件”的时候,可能还需要实例化“装饰者”天晓得实例化多少个!你的代码就特别依赖这些装饰类,从导致程序不容易维护, 但是这个通过工厂模式加以解决!第二章:工厂模式简单工厂我们再回头看一下之前的TeaStore类你有没有发现什么问题啊? 是不是出现了很多new啊,new 有问题吗? 凡是new的是不是都是具体的类啊. 这样TeaStore是不是依赖每一个具体的饮料类和装饰类啊. 这样一旦我减少或增加一种饮料或配料都要修改这个类,是不是很烦啊. 我们可不可以把这些创建对象的操作封装到一个其他类中,创建完毕后返回一个抽象的接口类型的对象.定义简单工厂类我们希望,只要TeaStore(茶店)给工厂下一个订单,工厂就可以把TeaStore需要的饮料生产出来. 订单格式为: 芝士火腿咖啡,如果是双芝士,就是芝士芝士咖啡.在TeaStore中使用简单工厂类但是我觉得对TeaStore来说还是太麻烦了,我希望TeaStore直接给工厂下一个订单,工厂就能生产出对应产品出来.Beverage t = bf.order("茶");System.out.println(t.desc() + "\t" + t.cost());// 来一杯芝士咖啡Beverage c1 = bf.order("芝士咖啡");System.out.println(c1.desc() + "\t" + c1.cost());// 来一份双芝士的咖啡.Beverage c2 = bf.order("芝士芝士咖啡");System.out.println(c2.desc() + "\t" + c2.cost());// 来一份芝士火腿茶Beverage c3 = bf.order("芝士火腿茶");System.out.println(c3.desc() + "\t" + c3.cost());}}◆来看一下现在依赖关系图有的人可能会觉得,你这样搞完只是TeaStore不依赖具体的类了,但是BeverageFactory还是依赖具体的类啊,没错,确实是这样。
1.设计模式概述如果把修习软件开发当做武功修炼的话,那么可以分为招式和内功。
招式:Java、C#、C++等编程语言;Eclipse、Visual Studio等开发工具;JSP、等开发技术;Struts、Hibernate、JBPM等框架技术;内功:数据结构、算法、设计模式、重构、软件工程每一位软件开发人员也都希望成为一名兼具淋漓招式和深厚内功的“上乘”软件工程师,而对设计模式的学习与领悟将会让你“内功”大增,再结合你日益纯熟的“招式”,你的软件开发“功力”一定会达到一个新的境界。
招式可以很快学会,但是内功的修炼需要更长的时间。
1.1 设计模式从何而来模式之父Christopher Alexander(克里斯托弗.亚历山大)———哈佛大学建筑学博士、美国加州大学伯克利分校建筑学教授、加州大学伯克利分校环境结构研究所所长、美国艺术和科学院院士。
“每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的成功的解决方案,无须再重复相同的工作。
”——《建筑的永恒之道》by Christopher AlexanderChristopher Alexander在《建筑的永恒之道》中给出了设计模式的定义,这些话可以总结出一句话那就是:“设计模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
”(设计模式的定义)1.2 软件设计模式又从何而来四人组(Gang of Four),简称GoFRalph Johnson,Richard Helm,Erich Gamma,John VlissidesGoF将模式的概念引入软件工程领域,这标志着软件模式的诞生。
软件模式(Software Patterns)是将模式的一般概念应用于软件开发领域,即软件开发的总体指导思路或参照样板。
软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等,实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。
软件模式与具体的应用领域无关,也就是说无论你从事的是移动应用开发、桌面应用开发、Web应用开发还是嵌入式软件的开发,都可以使用软件模式。
无论你是使用Java、C#、Objective-C、、Smalltalk等纯面向对象编程语言,还是使用C++、PHP、Delphi、JavaScript等可支持面向对象编程的语言,你都需要了解软件设计模式!我们可用一句大白话:“在一定环境下,用固定套路解决问题。
”1.3 软件设计模式的种类GoF提出的设计模式有23个,包括:有一个“简单工厂模式”不属于GoF 23种设计模式,但大部分的设计模式书籍都会对它进行专门的介绍。
设计模式目前种类:GoF的23种+ “简单工厂模式”= 24种。
1.4 软件设计模式有什么用?从高端来讲的话,那么作用大了去了,这里我们也体会不到,那么对于初学者来说,学习设计模式将有助于更加深入地理解面向对象思想, 让你知道:1. 如何将代码分散在几个不同的类中?2. 为什么要有“接口”?3. 何谓针对抽象编程?4. 何时不应该使用继承?5. 如果不修改源代码增加新功能?6. 更好地阅读和理解现有类库与其他系统中的源代码。
学习设计模式会让你早点脱离面向对象编程的“菜鸟期”。
1.5 如何学好设计模式设计模式的基础是:多态。
初学者:积累案例,不要盲目的背类图。
初级开发人员:多思考,多梳理,归纳总结,尊重事物的认知规律,注意临界点的突破,不要浮躁。
中级开发人员:合适的开发环境,寻找合适的设计模式来解决问题。
多应用,对经典则组合设计模式的大量,自由的运用。
要不断的追求。
1.6 设计模式总览表2.面向对象设计原则对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。
在面向对象设计中,可维护性的复用是以设计原则为基础的。
每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平。
面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则。
面向对象设计原则也是我们用于评价一个设计模式的使用效果的重要指标之一。
原则的目的:高内聚,低耦合2.1面向对象设计原创表2.1.1开闭原则案例return m_a + m_b;}else if (m_pare("-") == 0){return m_a - m_b;}else if (m_pare("*") == 0){return m_a * m_b;}else if (m_pare("/") == 0){return m_a / m_b;}}private:int m_a;int m_b;string m_operator;int m_ret;};/*缺点:如果增加取模的运算需要修改getResult成员方法,如果增加新功能的情况下要修改源代码,那么就会有修改出错的可能性。
我们应该在增加新的功能时候,不能影响其他已经完成的功能。
这就是对修改关闭,对扩展开放,叫做开闭原则*/void test01(){Caculaor* caculator = new Caculaor(10, 20, "+");cout << caculator->getResult() << endl;}/* 计算器开闭原则 start *///计算器的抽象类class AbstractCaculator{public:AbstractCaculator(int a,int b) :m_a(a), m_b(b){}virtual int getResult() = 0;protected:int m_a;int m_b;};//加法类class Plus : public AbstractCaculator{public:Plus(int a, int b) :AbstractCaculator(a, b){}virtual int getResult(){return m_a + m_b;}};//减法类class Minute : public AbstractCaculator{public:Minute(int a, int b) :AbstractCaculator(a, b){} virtual int getResult(){return m_a - m_b;}};void test02(){AbstractCaculator* caculator = NULL;caculator = new Plus(10,20);cout << caculator->getResult() << endl;delete caculator;caculator = new Minute(10,20);cout << caculator->getResult() << endl;}/* 计算器开闭原则 end */int main(){//test01();test02();2.1.2迪米特法则案例#define_CRT_SECURE_NO_WARNINGS#include<iostream>#include<string>#include<list>using namespace std;//楼盘基类class AbstractBuilding{public:AbstractBuilding(string quality) :m_quality(quality){}virtual void sale() = 0;string getQuality(){return m_quality;}protected:string m_quality; //楼盘品质};//A楼盘class BuildingA : public AbstractBuilding{public:BuildingA(string quality) :AbstractBuilding(quality){}virtual void sale(){cout << "A楼盘售卖" << m_quality << "的房子" << endl;}};//B楼盘class BuildingB : public AbstractBuilding{public:BuildingB(string quality) :AbstractBuilding(quality){}virtual void sale(){cout << "B楼盘售卖" << m_quality << "的房子" << endl;}//房屋中介class BuildingMediator{public:BuildingMediator(){AbstractBuilding* building = NULL;building = new BuildingA("低档品质");this->addNewBuilding(building);building = new BuildingB("高档品质");this->addNewBuilding(building);}void addNewBuilding(AbstractBuilding* building){m_list.push_back(building);}AbstractBuilding* findBuilding(string quality){for(list<AbstractBuilding*>::iterator it = m_list.begin(); it != m_list.end();it ++){if ((*it)->getQuality().compare(quality) == 0){return *it;}}return NULL;}private:list<AbstractBuilding*> m_list;};void test01(){BuildingMediator* mediator = new BuildingMediator;AbstractBuilding* building = mediator->findBuilding("高档品质");if (building != NULL){building->sale();}else{cout << "没有符合要求的楼盘!" << endl;}}2.1.3合成复用原则案例#define_CRT_SECURE_NO_WARNINGS#include<iostream>using namespace std;class Car {public:virtual void run() = 0;};class BWMCar : public Car{public:virtual void run(){cout << "宝马车启动..." << endl;}};class DazhongCar : public Car{public:virtual void run(){cout << "大众车启动..." << endl;}};class PersonA : public BWMCar{public:void drive(){run();}};void test01(){PersonA* person = new PersonA;person->drive();}/*合成复用原则对于继承和组合优先使用组合*/class PersonB{public:PersonB(Car* car){pCar = car;}void drive(){pCar->run();}~PersonB(){if (pCar != NULL){delete pCar;}}private:Car* pCar;};void test02(){PersonB* person = new PersonB(new BWMCar);person->drive();delete person;person = new PersonB(new DazhongCar);person->drive();delete person;}int main(){//test01();test02();system("pause");return EXIT_SUCCESS;}2.1.4依赖倒转原则案例传统的设计模式通常是自顶向下逐级依赖,这样,底层模块,中间层模块和高层模块的耦合度极高,若任意修改其中的一个,很容易导致全面积的修改,非常麻烦,那么依赖倒转原则利用多态的先天特性,对中间抽象层进行依赖,这样,底层和高层之间进行了解耦合。