//考试主要在设计模式,设计原则上考察较多,多看看老师ppt的类图,自己手动画画

//问答题: 四种多态变量形式,继承的八种,三种空间分配,多重单重继承优劣。。。。

第一部分  对象,类等基础概念

1、对象概念

对象:从问题域中客观存在的事物出发来构造软件系统,用对象作为对这些事物的抽象表示,并作为系统的基本构成单位。

属性:表示事物的静态特征

服务(操作):表示事物的动态特征。

封装:对象的属性服务结合一体,成为一个不可分割的实体,对外不暴露细节。

分类:对事物进行分类。把具有相同属性和相同服务的对象归为一类,类是这些对象的抽象描述,每个对象是它的类的一个实例。

消息:通过消息通讯,对象通过消息动态联系

关联: 对象之间静态关系

聚合:复杂的对象可以用简单的对象作为其构成部分。

继承:通过不同程度的抽象,可以把类分为特殊的类和一般的类,特殊的类继承一般的类服务与属性,简化系统的构造。

沃夫假说:一个语言中的某些表达,无论如何也无法用另一门语言来表示。

丘奇猜想:任何具有明确步骤的计算都可以被图灵机实现。

  1. 代理与团体

代理通过责任完成你的要求。

责任描述行为。

行为的启动是将消息传递对此行动复制的代理对象来实现。

消息对行为的要求进行编码,伴随执行附加参数来传递。

接收器:消息接受的对象。接受消息所包含的行为责任。

信息隐藏原则:客户不需要了解要求的实现方式。

所有人隐藏在消息传递过程中。

消息传递与过程调用:

消息传递:每条消息必有一个接收器。解释(响应)由接收器决定。

过程调用:没有上述特点

对象2:可以是面向对象中一个代理团体,一个对象扮演一个角色,提供服务。

对象性质:

封装性:消息隐藏。

自治性:主动数据。

通信性:并发。

暂存性:作用域

永久性:文档串行化

方法绑定与改写:

接收器搜索并执行相应的方法以响应给定的消息。

如果没有找到匹配的方法,搜索就会传导到此类的父类。搜索会在父类链上一直进行下去,直到找到匹配的方法,或者父类链结束。

如果能在更高类层次找到相同名称的方法,所执行的方法就称为改写了继承的行为。

多态性:一般类中定义的属性与方法,在特殊类中不改变其名字,但通过不同实现,有自己的数据类型和行为。

第二部分    抽象

  1. 抽象层次

一、团体:在最高级别上,程序被视为一个对象的“团体”,这些对象间相互作用,以完成共同的目标。

团体的两重含义:1.程序员组成的团体,在现实中相互作用,开发程序2.程序对象组成的团体,在虚拟世界中相互作用,完成目标。

二、单元:许多语言允许协同工作的对象组合到一个“单元”(unit)中。这些单元允许某些特定的名称暴露在单元以外,而其他特征则隐藏在单元中。

三、CS:处理两个独立对象之间的交互。两个对象间交互时涉及两层抽象:一个对象(服务者, server)向另一个对象(客户, client)提供服务,二者之间以通信来交互。

四、服务实现方式:考虑抽象行为的具体实现方式。

五、具体实现:实现方法:考虑抽象行为的具体实现方式。

  1. 抽象形式

正在上传…重新上传取消

分治法:常用的一种抽象形式是将一层划分为多个组成部分。例子:汽车是由发动机、传动机构、车身和车轮组成的。Has a

特殊化分层 :该抽象形式称为特殊化或具体化。是使用特殊化的层次来构建抽象。

Is a

不同视角:,是对同一件物品提供不同的视角.对同一对象描述出不同的特性. is a

分类:当系统中组件数量变大时,常用分类(Catalogs)来进行组织。

服务视角:对接口和实现的划分,不仅从高层的角度对设计易于理解,而且使软件组件的替换成为可能。接口描述软件组件所提供的服务,却不必描述完成服务所使用的技术。

组合:组合,是另一个由简单部分构建复杂结构的有力技术。

模式:以前的问题可以作为一个解决问题的模型,略做修改可能就能解决新问题了。

  1. 继承

Is a

Has a

  1. 发展简史

1、汇编语言:最早的抽象机制

2、过程/函数

3、部分信息隐藏

4、堆栈例

5、模块:解决全局名称空间拥挤问题。堆栈例:

希望公开信息:接口

限制存取信息:堆栈数据

模块提供了将名称空间划分成两个部分的能力。

公有部分可以在模块外存取,私有部分只能从模块内存取。

模块不允许实现实例化。

实例化是一种能够建立数据区域多份拷贝的能力。

6、抽象数据类型

目标:1).定义抽象,创建多个实例;

  1. .使用实例,知其所提供操作,不必知道如何实现。
  2. ADT通过抽象规范来定义。
  3. 把接口的概念和实现的概念分离开来
  1. 以服务为中心

汇编语言和过程:功能为中心;

模块和ADT:数据为中心;(结构、表示、操纵)

面向对象:服务为中心。

  1. 消息、继承和多态。

ADT基础上增加的新思想。

第三部分 类

数据类型两个方面:外部用户/实现者。

实例变量/数据成员/数据字段:对象内部变量

可视性修饰符

定义和实现分离:

Java,C#:方法主体直接放在类定义中。

C++:分离

接口:

不提供实现

接口定义新类型,可以声明变量

类的实例可以赋值给接口类型变量

向前定义:可以声明一个类而不定义它

  1. 多个互相引用的类(相互递归)
  2. Java全文扫描。C++向前定义

内部类

java的非静态内部类有个外部类的引用outer,使用这个变量可以引用外部的所有变量,包括private

静态的java内部类也叫做嵌套类,静态的内部类就没有外部的引用了,但是也只能调用外部的静态方法和变量

c++的内部类几乎等同于语法上的嵌套,而C++的内部类不能访问外部类的private变量,想访问的话必须在内部类中声明外部类为friend class

类的数据字段(类属性):被一个类的所有实例共享的公共数据字段。

对象本身不对共享字段初始化。

内存管理器自动将共享数据初始化为某特定值,每个实例去测试该特定值。

第一个进行测试的做初始化。

Java和C++使用修饰符static创建共享数据字段。

Java:静态数据字段的初始化是在加载类时,执行静态块来完成。

c++:由基本数据类型表示的静态数据字段可以在类的主体中进行初始化。

在类外对静态数据字段进行初始化。

类的成员函数:

成员函数。不能访问非静态成员。

无this

构造和析构函数不能为静态成员。

  1. 消息、实例和初始化

消息:

类型:

对象接收多个消息,响应不同(文理科)

同一消息给多个对象,响应不同(考学结果)

广播,可响应可不响应

定义:对象间相互请求或相互协作的途径。

语法:

接收器:接受消息的对象

参数:用于响应消息

消息选择器:表示待传递的消息语法

  1. b(c) // A:接收器 b:消息选择器 c:参数

静态与动态语言

动态类型语言与静态类型语言之间的差异在于变量或数值是否具备类型这种特性。

静态:类型和变量联系在一起(Java,C++,C#,Pascal)

动态:变量看作名称标识,类型和数值联系在一起。(SmallTalk,Python)

面向对象静态:C++,Delphi pascal,Eiffel,Java

面向对象动态:Objective-c,Smalltalk,Dylan,Python

非面向对象静态:Ada,Algol,C,Fortran,Haskell,ML,Modula

非面向对象动态:APL,Forth,Lisp,Prolog,Snobol

从方法内部存取接收器(伪变量):

在大多数面向对象语言中,接收器并不出现在方法列表中,而是隐藏于方法的定义中。只有当必须从方法体内部去存取接收器的数值时,才会使用伪变量(pseudo-variable)。

不需要声明,不能被更改

在使用时就好像作为类的一个实例

默认隐藏:很多编程语言中,对接收器伪变量的使用都可以被忽略。如果在没有引用接收器的条件下,访问一个数据字段或者调用一个方法,那么意味着接收器伪变量将作为消息的主体。

Java,C++:this

Eiffel:Current

Smalltalk,object-c:self

对象的创建:

变量声明与初始化结合c++

A a;

变量声明与创建分离JAVA C++

A *a=new A();

A a=new A();

Smalltalk

aCard <- PlayingCard new.

对象数组的创建:

C++:结合

对象使用缺省构造函数来初始化。

Java:new仅创建数组。数组包含的对象必须独立创建。

指针和内存分配:

所有面向对象语言在它们的底层表示中都使用指针,但不是所有语言都把这种指针暴露给程序员。

对象引用实际是存在于内部表示中的指针

内存回收

1、在程序中显式制定不再使用的对象,将其使用内存回收。

C++:delete
Object Pascal:free

2、垃圾回收机制(Java,C#,Smalltalk)

时刻监控对象的操作,对象不再使用时,自动回收其所占内存。

通常在内存将要耗尽时工作。

确保动态分配的内存对象都有一个指定的属主。

引用计数:引用共享对象的指针的计数值。

内存分配:

三种方式:静态的,栈式的,和堆式的

静态存储分配:

静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间。

栈式存储分配:

栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的。

在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存。

栈式存储分配按照先进后出的原则进行分配。

堆式存储分配:

静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。

堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。

const常量,不允许改变。

final仅断言相关变量不会赋予新值,并不能阻止在对象内部对变量值进行改变。如对消息的响应。

Java,Smalltalk中类本身是对象。那那么什么类代表了对象所属的类别,即这个类是什么类。有一个特殊的类,一般称为Class,这就是类的类。具有创建实例,返回类名称,返回类实例大小,返回类实例可识别消息列表。

对象产生:

三种基于类(class-based),基于原型(prototype-based)和基于元类 (metaclass-based)的对象模型。

smallTalk元类:
根类Object。所有类是Object的派生类。

每个类是其元类的实例。

每个元类是类Meta的实例。

所有元类是类Class的派生类。

元类是描述类的类

类的继承关系与相应的元类的继承关系是平行的

如果B是A的子类,则B的元类也是A的元类的子类

反射与内省

用于反射和内省的技术分为两大类

获取理解当前计算状态的特征

用于修改的特征:增加新的行为

Java获取类对象:

Class aClass = aVariable.getClass();

C++获取类对象:

typeinfo aClass = typeid(AVariable);

第四部分 继承

  1. 继承

把继承作为一种扩展同时也作为一种收缩的思想,正是面向对象技术强大的原因,同时也会在正常的部署中引起混淆 。

继承总是向下传递的,因此一个类可以从它上面的多个超类中继承各种属性 。

is-a检验(“是一个”检验):检验两个概念是否为继承关系。

符合子类型关系:一般所说的”is a"关系,你必须保证新类的行为与父类完全一致.

子类型与子类区别:

如果说新类是已存在类的子类型,那么这个新类不仅要提供已存在类的所有操作,而且还要满足于这个已存在类相关的所有属性。

继承的作用:

代码复用

概念复用。共享方法的定义。

父类子类关系:

    1、子类实例必须拥有父类的所有数据成员。

2、子类的实例必须至少通过继承实现父类所定义的所有功能。

3、这样,在某种条件下,如果用子类实例来替换父类实例,那么将会发现子类实例可以完全模拟父类的行为,二者毫无差异。

替换原则:指如果类B是类A的子类,那么在任何情况下都可以用类B来替换类A,而外界毫无察觉。

访问控制:

Java与C++中权限

private:只能用于父类内部。

public:可用于类定义外部。

protected(注意区别):

Java中:默认对本包和所有子类可见。

C++中:只能被本类或者子类访问。

在java中有public、protected、private三种显示的修饰符用于控制可见性,package不是显示的修饰符,它是隐含的,即如果在类、变量等前没加显示的可见性修饰符,那它就是package级别的。如果在类的定义中没有指定package,那么java会把它放在缺省包中,一般来说这个缺省的包就是当前目录。

在子类中的方法如果重载了父类的方法,那么该方法的可见级别应更低或者相同,如父类中的方法是public,那么子类中方法必须是public。

可见/访问性

在同一类中

同一包中

不同包中

同一包子类中

不同包子类中

public

yes

yes

yes

yes

yes

protected

yes

yes

no

yes

yes

package

yes

yes

no

yes

no

改写:

子类有时为了避免继承父类的行为,需要对其进行改写

语法上:子类定义一个与父类有着相同名称且类型签名相同的方法。

运行时:变量声明为一个类,它所包含的值来自于子类,与给定消息相对应的方法同时出现于父类和子类。

C++中,需要父类中使用关键字Virtual来表明这一含义.  

  1. 继承的形式

特殊化(specialization)继承子类是父类型的子类型。

在这种形式下,新类是基类的一种特定类型,它能满足基类的所有规范。
用这种方式创建的总是子类型,并明显符合可替换性原则。

与规范化继承一起,这两种方式构成了继承最理想的方式,也是一个好的设计所应追求的目标。

规范化(specification)继承:父类规定行为,不实现行为,由子类实现。

规范化继承用于保证派生类和基类具有某个共同的接口,即所有的派生类实现了具有相同方法界面的方法。

基类中既有已实现的方法,也有只定义了方法接口、留待派生类去实现的方法。派生类只是实现了那些定义在基类却又没有实现的方法。

Abstract  class的继承

规范化继承可以通过以下方式辨认:基类中只是提供了方法界面,并没有实现具体的行为,具体的行为必须在派生类中实现。

构造继承:子类使用父类提供的行为,但不是父类的子类型。

一个类可以从其基类中继承几乎所有需要的功能,只是改变一些用作类接口的方法名,或是修改方法中的参数列表。

即使新类和基类之间并不存在抽象概念上的相关性,这种实现也是可行的。

当继承的目的只是用于代码复用时,新创建的子类通常都不是子类型。这称为构造子类化。

一般为了继承而继承,如利用一些工具类已有的方法。

树-独木舟

堆栈-队列

写二进制文件-写学生信息文件

泛化子类化:子类修改或改写父类的某些方法

派生类扩展基类的行为,形成一种更泛化的抽象。

与特化子类化相反,对基类已存在的功能进行修改或扩展。

Window-ColoredWindow

泛化子类化通常用于基于数据值的整体设计,其次才是基于行为的设计。

扩展继承:子类对父类增加新功能,但并不改变任何继承父类的行为

如果派生类只是往基类中添加新行为,并不修改从基类继承来的任何属性,即是扩展继承。(泛化子类化对基类已存在的功能进行修改或扩展,扩展子类化则是增加新功能)而且并没有被修改,因此扩展继承并不违反可替换性原则,用这种方式构建的派生类还是派生类型。

限制继承:子类限制继承使用父类的某些行为

如果派生类的行为比基类的少或是更严格时,就是限制继承。

常常出现于基类不应该、也不能被修改时。

限制继承可描述成这么一种技术:它先接收那些继承来的方法,然后使它们无效。

由于限制继承违反了可替换性原则,用它创建的派生类已不是派生类型,因此应该尽可能不用。

变体子类化:子类与父类都是对方的变体

两个或多个类需要实现类似的功能,但他们的抽象概念之间似乎并不存在层次关系。

控制机械鼠标=控制轨迹球

但是,在概念上,任何一个类作为另一个类的子类都不合适

因此,可以选择其中任何一个类作为父类,并改写与设备相关的代码

相比于变体子类化,更好的方法是将两个类的公共代码提炼成一个抽象类,并且让这两个类都继承于这个抽象类。

与泛化子类化一样,但基于已经存在的类创建新类时,就不能使用这种方法了。

合并继承:子类的特征来着多个父类

可以通过合并两个或者更多的抽象特性来形成新的抽象。

一个类可以继承自多个基类的能力被称为多重继承 。

助教

  1. 静态行为和动态行为

静态类:变量的静态类是指用于声明变量的类。

动态类:变量的动态类指与变量所表示的当前数值相关的类。

在编译时消息传递表达式的合法性不是基于接收器的当前动态数值,而是基于接收器的静态类来决定的。

A a=new b() ,只能调用类A拥有的方法,b可以改写这些方法,但不能调用b的方法。

向下造型(反多态)

做出数值是否属于指定类的决定之后,通常下一步就是将这一数值的类型由父类转换为子类。

向下造型也叫做向下类型转换或强制类型转换,即子类的引用指向父类的对象。将父类对象的类型转换成子类的类型。 A a=new B();B b=(B) a;

向上造型:

向上造型也叫做向上类型转换或自动类型转换,即父类的引用指向子类的对象。将子类对象的类型转换成父类的类型。

多态变量:

Java,Smalltalk等变量都是多态的。

C++声明为简单类型的变量,非多态。使用指针或引用;相关方法声明为virtual;才可以实现多态消息传递。

如果方法所执行的消息绑定是由最近赋值给变量的数值的类型来决定的,那么就称这个变量是多态的。

最小静态空间分配

C++使用最小静态空间分配策略,运行高效。

只分配基类所需的存储空间。

为了防止采用这种策略时因为多态而引发的程序错误(具体参照P179),C++改变了虚拟方法的调用规则:

对于指针/引用变量:当信息调用可能被改写的成员函数时,选择哪个函数取决于接收器的动态数值。

对于其他变量:调用虚拟成员函数的方式取决于静态类(变量声明分类),而不取决于动态类(变量所包含的实际数值的类)。

子对象付给父对象(会slicing,切割),再由父对象转为子对象丢失对象信息。

最大静态空间分配

分配变量值可能使用的最大存储空间。

这一方案不合适,因为需要找到最大的对象,就需要对继承树上的所有对象都进行扫描,然后找到需要分配最大内存的对象才能。

动态内存分配

栈中不保存对象值。

栈通过指针大小空间来保存标识变量,数据值保存在堆中。

指针变量都具有恒定不变的大小,变量赋值时,不会有任何问题。

Smalltalk、Java都采用该方法。

复制和克隆

浅复制(shallow copy):共享实例变量。

深复制(deep copy):建立实例变量的新的副本。

Java clone ()   JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。

要说明的有两点:

一是拷贝对象返回的是一个新对象,而不是一个引用。

二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

operator = 、拷贝构造函数 和 clone()方法

第五部分 多重继承 多态

  1. 多重继承

多重继承:一个对象可以有两个或更多不同的父类,并可以继承每个父类的数据和行为。

名称歧义

解决方案:1、使用全限定名。

不够理想:语法上与其他的函数调用语法不同

程序员必须记住哪个方法来自于哪个类

2、使用重定义和重命名的结合

重定义:

class GraphicalCardDeck : public CardDeck, public GraphicalObject {public:virtual Card*draw () { return CardDeck::draw(); }virtual void draw(Graphics *g) { GraphicalObject::draw(g); }}GraphicalCardDeck gcd;Graphis g;gcd->draw(); // selects CardDeck drawgcd->draw(g); // selects GraphicalObject

重命名:

class GraphicalCardDeck : public CardDeck, public GraphicalObject {public:virtual void draw () { return CardDeck::draw(); }virtual void paint () { GraphicalObject::draw(); }}GraphicalCardDeck gcd;gcd->draw(); // selects CardDeck drawgcd->paint(); // selects GraphicalObject

3、引入辅助类

具体整两个Parent类 ,分别继承CardDeck与GraphicalObject ,最后继承Parent类 都实现,ppt实现有误最后继承的类不需要重写那几个virtual 的cardDeckDraw()等方法

Class CardDeckParent : public CardDeck {Public :virtual void draw () { cardDeckDraw ();}virtual void cardDeckDraw () { CardDeck :: draw ();}};Class GraphicalObjectParent : public GraphicalObject {Public :virtual void draw () { goDraw ();}virtual void goDraw () {GraphicalObject :: draw ();}};Class GraphicalCardDeck : public CardDeckParent, GraphicalObjectParent {Public :};

构造函数与析构函数

构造函数也遵从先祖先(基类),再客人(成员对象),后自己(派生类)的原则,有多个基类之间则严格按照派生定义时从左到右的顺序来排列先后。析构函数调用正好相反。

多态形式

重载(专用多态):类型签名区分

public void example (int x){……}public void example (int x,double y){……}public void example (string x){……}

改写(包含多态):层次关系中,相同类型签名

Class parent{public void example(int x){……}}Class child extends parent{//same name,different method bodypublic void example(int x){……}}

多态变量(赋值多态):声明与包含不同

Parent p=new child();

泛型(模板):创建通用工具

最常用的软件复用机制:继承和组合。

组合和继承的比较:

组合是较为简单的一种技术。优点是在特定的数据结构中需要执行哪些操作。无需考虑列表类所定义的所有操作。

继承无法知道一个方法是否可以合法地应用于集合。

使用继承构建数据抽象的代码的简洁性是继承的一个优点

  1. 重载

重载是在编译时执行的,而改写是在运行时选择的。

重载是多态的一种很强大的形式。

非面向对象语言也支持。

函数类型签名:关于函数参数类型、参数顺序和返回值类型的描述。

类型签名通常不包括接收器类型。

范畴:范畴定义了能够使名称有效使用的一段程序,或者能够使名称有效使用的方式。(局部变量/public成员)

通过类型签名和范畴可以对重载进行两种分类:基于具有不同范畴的方法;基于具有不同类型签名的方法。

基于具有不同范畴的方法:相同的名称可以在不引起歧义且不造成精度损失的情况下出现于多个不同的范畴。比如继承。

基于类型签名的重载:

多个过程(或函数、方法)允许共享同一名称,且通过该过程所需的参数数目、顺序和类型来对它们进行区分。

即使函数处于同一上下文,这也是合法的。

关于重载的解析,是在编译时基于参数值的静态类型完成的。

造型

x是y的父类

上溯造型

X a=new X();Y b=new Y();a=b;  //将子类对象造型成父类对象,相当做了个隐式造型:a = (X)b;

下溯造型

X a=new X();Y b=new Y();X a1=bY b1=(Y)a1

重定义

当子类定义了一个与父类具有相同名称但类型签名不同的方法时,发生重定义。

类型签名的变化是重定义区别于改写的主要依据。

两种不同的技术解析重定义:融和模型和分级模型。

JAVA使用融和模型

class Parent {public void example (int a){System.out.println(“in parent method”);}}class Child extends Parent {public void example (int a,int b){System.out.println(“in child method”);}}

使用时

Child aChild = new Child();

aChild.example(3);

C++每个范畴都维护自己独立的列表。

为了使名称与方法匹配,需要依次对各个范畴进行检查,因此将其标识为分级的。

通过在子类中重定义两个方法来实现与Java模型相同的效果

class Parent {public:
void example (int a){cout<<“in parent method”;}}class Child extends Parent {public:void example (int a){Parent::example(a);}void example (int a,int b){cout<<“in child method”;}}
  1. 改写

如果子类的方法具有与父类的方法相同的名称和类型签名,称子类的方法改写了父类的方法。

各种语言在如何通过代码实现标识改写这方面存在着差异。(Java不需要,C++需要virtual)

改写和重载的差异

对于改写来说,方法所在的类之间必须符合父类/子类继承关系,而对于简单的重载来说,并无此要求。

如果发生改写,两个方法的类型签名必须匹配。

重载方法总是独立的,而对于改写的两个方法,有时会结合起来一起实现某种行为。

重载通常是在编译时解析的,而改写则是一种运行时机制。对于任何给定的消息,都无法预言将会执行何种行为,而只有到程序实际运行的时候才能对其进行确定。

两种不同的关于改写的解释方式:

1.代替(replacement):在程序执行时,实现代替的方法完全覆盖父类的方法。即,当操作子类实例时,父类的代码完全不会执行。

2.改进(refinement):实现改进的方法将继承自父类的方法的执行作为其行为的一部分。这样父类的行为得以保留且扩充。super

延迟方法

如果方法在父类中定义,但并没有对其进行实现,那么我们称这个方法为延迟方法。延迟方法有时也称为抽象方法,并且在C++语言中通常称之为纯虚方法。

延迟方法有时也称为抽象方法,并且在C++语言中通常称之为纯虚方法。

延迟方法的一个优点就是可以使程序员在比实际对象的抽象层次更高的级别上考虑与之相关的活动。

延迟方法更具实际意义的原因:在静态类型面向对象语言中,对于给定对象,只有当编译器可以确认与给定消息选择器相匹配的响应方法时,才允许程序员发送消息给这个对象。

c++:virtual xxx(XX xx..)=0;

Java  C#:abstract

改写与遮蔽存在着外在的语法相似性

类似于重载,改写区别于遮蔽的最重要的特征就是,遮蔽是在编译时基于静态类型解析的,并且不需要运行时机制。

几种语言需要对改写显式声明,如果不使用关键字,将产生遮蔽。

 Class A{Public: int x=12;}Class B: public A{Public: int x=42;}A *a=new B;Cout<<a.x;// 12

差异:

1.改写 父类与子类的类型签名相同,并且在父类中将方法声明为虚拟的。

2.遮蔽 父类与子类的类型签名相同,但是在父类中并不将方法声明为虚拟的。

3.重定义 父类与子类的类型签名不同。

协方差与反协方差:

很少有改变类型签名的需求,通常将类型在其继承层次上提升或降低。

当一个类型降低类型层次作为子类时,将使用协方差变化术语。

反之,当一个类型由子类化反向提升类型层次时,将使用反协方差变化术语。

情况:

1、考虑改变方法的返回值类型?(如果子类可接受的数值集合范围大于父类可接受的数值集合范围)

2、如果子类可接受的数值集合范围大于父类可接受的数值集合范围

3、如果子类可接受的数值集合范围小于父类可接受的数值集合范围(值传递)

  1. 多态变量

多态变量是指可以引用多种对象类型的变量。

这种变量在程序执行过程可以包含不同类型的数值。

对于动态类型语言,所有的变量都可能是多态的。

对于静态类型语言,多态变量则是替换原则的具体表现。

作用

多态接收器功能的强大之处表现在消息传递与改写相结合时。这种结合是软件框架开发的关键。

一般框架系统中的方法分为两大类:

在父类中定义基础方法,被多个子类所继承,但不被改写;

父类定义了关于多种活动的方法,但要延迟到子类才实现。

多态变量形式

简单变量:

Parent *p=new Child();

接收器变量:

多态变量最常用的场合是作为一个数值,用来表示正在执行的方法内部的接收器。伪变量 :smalltalk:self,C++,Java,C#:this

反多态:向下造型 child=parent;

将父类变量赋值给一个声明为子类的变量

该取消多态赋值的过程,也称为反多态。

纯多态(多态方法):多态方法

支持可变参数的函数。

支持代码只编写一次、高级别的抽象

以及针对各种情况所需的代码裁剪。

通常是通过给方法的接收器发送延迟消息来实现这种代码裁剪的。

  1. 泛型

泛型:泛型将名称定义为类型参数。

在编译器读取类描述时,无法知道类型的属性,但是该类型参数可以像类型一样用于类定义内部。

在将来的某一时刻,会通过具体的类型来匹配这一类型参数,这样就形成了类的完整声明。

Java:

Public class A<T>{}

Public interface  A<T>{}

C++:

Template<class T>

例子:

Apple类:使用printOn方法将自身输出。

Orange类:使用writeTo方法将自身输出。

二进制提供

希望将Apple对象和Orange对象保存在同一个列表中,并且使用一个多态函数将它们输出。

方案一:

使用instanceof 判断Apple还是Orange

方案二:

1、定义一个公共的父类,具有共同行为

Class Fruit {public:virtual void print (ostream &)=0;//纯虚方法};

2、两个全局的普通函数(为了适应模板)

void print(const Apple &a ,ostream &out){a.printOn(out);}void print(const Orange &a ,ostream &out){a.writeOn(out);}

3、使用模版,创建一个fruit adapter类,将以Apple或者Orange为参数,同时符合水果的定义

template <class T>class FruitAdapter : public Fruit {public:FruitAdapter (T & f):theFruit (f){ }T & value ( ){ return theFruit ;}virtual void print ( ostream & out ){print(theFruit,out);public:T & theFruit;};

4、使用模版函数简化适配器的创建过程

template <class T>Fruit * newFruit ( T & f ){return new FruitAdapter <T>(f);};

5、最终:

Apple anApple(“Rome”);Orange anOrange;List<Fruit *> fruitList;fruitList.insert(newFruit(anApple));fruitList.insert(newFruit(anOrange));List<Fruit *> ::iterator start = fruitList.begin();List<Fruit *> ::iterator stop = fruitList.end();For ( ;start!=stop; ++start) {Fruit & aFruit = *start;aFruit.print(cout);}
  1. 框架

对于一类相似问题的骨架解决方案。

通过类的集合形成,类之间紧密结合,共同实现对问题的可复用解决方案

继承和改写的强大能力体现

最常见的框架

Java中的GUI框架

Web开发中的Struts框架

使用继承的两种方式:

代码复用:基本方法,对问题的现存的解决方案。

概念复用:特化方法,用于特定应用的解决方案。

倒置库:

框架改变了应用程序(开发者定义的代码)与库代码之间的关系

传统的应用程序中

应用程序特定的代码定义了程序执行的总体流程

在框架中

控制流是由框架决定的,并且随应用程序的不同而不同

新的应用程序的创建者只需改变供框架调用的例程即可,而无需改变总体结构.

框架占主导地位,而应用程序特定的代码处于次要位置.

  1. 对象互连

一种考虑对象互连的方式就是研究可视性依赖性这两个概念。

可视性:描述了关于名称的特性,通过该名称句柄可以存取对象,如果对象的名称是合法的且代表该对象,那么在这个特定环境下该对象就是可见的。描述可视性的相关术语还包括标识符的范畴

依赖性:将两个对象或者类联系起来,在不存在另外一个对象的条件下,如果一个对象的存在无任何意义,就说该对象依赖于另外那个对象。例如: 子类几乎总是依赖于它的父类

  1. 内聚与耦合

耦合(coupling)和内聚(cohesion)的思想提供了一个框架,用于评价对象和类的应用是否有效。

耦合:描述类之间的关系

内聚:描述类内部的关系。

耦合种类:(从最差的耦合到较好的耦合)

内部数据耦合:

内部数据耦合发生在当一个类的实例直接修改另外一个类中的本地数据值(实例变量)时。

全局数据耦合:

全局数据耦合发生在两个或者更多个类型都依赖于公用的全局数据结构而绑定到一起的时候。

全局变量控制多个类。

控制(或顺序)耦合:

一个类必须以一种由任何位置控制的特定的顺序来执行操作。class A{dofirst();doSecond();doThird();}

组件耦合:组件耦合发生在一个类包含的数据字段或数值为另外一个类的实例时。class A{ B b;}

参数耦合:(方法参数调用)

参数耦合发生在一个类必须调用另外一个类的服务和例程时,此时两个类之间所发生的唯一关系就是一个类需要为另一个类提供参数数目、类型和返回值类型。class A{ m1(B b){b.m2();}}

子类耦合:(继承)

子类耦合是面向对象编程所特有的,描述了一个类与其父类之间的关系。通过继承,子类的实例可以被看成父类的实例。

内聚:类的内部内聚性是该结构中各个元素之间绑定程度的量度。

种类:从最弱的内聚到最强的内聚:

随机内聚:对程序随意划分

逻辑内聚:算术函数库

时间内聚:如实现程序初始化的类

通信内聚:数据或者设备的manager

顺序内聚:避免顺序耦合

功能内聚:类中元素通过执行特定功能关联起来

数据内聚:数据结构

*第六部分 UML//不是很重要捏

  1.   UML体系结构

任何语言都有语法和语义两个方面。

UML采用元-元模型、元模型、模型和用户对象四个层次来定义其体系结构。

作为一种建模语言,UML的定义包括UML语义和UML表示法两个部分。

  1. UML符号

活动者(Actor) :

活动者是作用于系统的一个角色或者说是一个外部用户。活动者可以是一个人,也可以是使用本系统的外部系统。

活动者名

用例(Use Case):

用例是对活动者使用系统的一项功能的交互过程的陈述。

对象类class:

对象类(类)是具有相同属性和相同操作的对象的集合。

接口(Interface):

接口是一种抽象类,它对外提供一组操作,但自己没有属性和方法(操作的实现),它是在没有给出对象实现的情况下对对象行为的描述。

包(Package):

包也是一种模型元素,可以把语义相近的模型元素组织在一个包里,增加对模型元素的可维护性。

组合(Composition):

组合关系用于表示对象之间部分和整体关系,关系很紧密。

如果组成被销毁,其部分也必须被销毁,或者依附于其它组成,即不允许游离的部分存在!

在UML中,带有实心箭头的关联来表示组合,箭头指向组成类。

用实心菱形的实线来表示,菱形指向整体

Class Hand{

Finger f;

}

聚合(Aggregation):

聚合关系也用于表示对象之间部分和整体关系,但关系比较松散。

组合关系表示整体和部分的关系比较强,而聚集表示整体和部分的关系比较弱;在组合关系中,代表整体的对象如果销毁了,那么代表部分对象也随之销毁;而在聚集中代表整体的对象如果销毁了,代表部分的对象不一定销毁。

聚合关系也是通过成员对象来实现的,其中成员对象时整体对象的一部分,但是成员对象可以脱离整体对象而独立存在

空心菱形的实线表示,菱形指向整体

泛化(Generalization):

泛化用于表示对象之间一般和特殊的结构关系。

泛化关系用带空心三角箭头的实线来表示,箭头从子类指向父类.

代码实现时,使用面向对象的继承机制来实现

实现(Realization):

实现是指一个模型元素(如:类)是另一个模型元素(如:接口)的实现。

是接口与实现类之间的关系。类实现了接口,类中的操作实现了接口中所有声明的所有的抽象操作。

实现关系使用带空心三角箭头的虚线来表示,箭头从实现类指向接口

实现类接口

依赖(Dependency):

依赖表示两个或多个模型元素之间语义上的关系 。

是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。

在代码中,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责

Class A{ void a(B b ){  b.c();  }}

依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类

AB

关联(Association):

关联就是类或对象之类链接的描述。

是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师父和徒弟等。

关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系和组合关系

关联可以是双向的,也可以是单向的。在UML类图中,**双向的关联可以用带两个箭头或没有箭头的实线来表示;单向的关联用带一个箭头的实现来表示;箭头从使用类指向被关联类。**在关联线两端标注角色名,代表两种不同的角色

注释(Comment) :

注释没有特定的语义,它用于对其他模型元素的补充说明。

消息(Message):

  1. UML概念模型

UML构造块:

1. 事物(Things)

2. 关系(Relationships)

3. 图(Diagrams)

UML的事物:

1.结构事物(Structural things)

2.动作事物(Behavioral things)

3.分组事物(Grouping things)

4.注释事物(Notational things)

UML模型图:

用例图:

从用户角度描述系统功能,并指出各功能的操作者。

正在上传…重新上传取消

静态图:
包括类图、对象图和包图。

类图

类图是用类和它们之间的关系描述系统的一种图示。

类、对象和它们之间的关联是面向对象技术中最基本的元素。类模型和对象模型揭示了系统的结构。

正在上传…重新上传取消

属性:可视性 属性名 [多重性] :类型 = 初始值。 +,-,#

操作:可视性 操作名 (参数列表):返回列表

正在上传…重新上传取消

行为图:

描述系统的动态模型和组成对象间的交互关系。

状态图描述类的对象所有可能的状态以及事件发生时状态的转移条件。

活动图描述满足用例要求所要进行的活动以及活动间的约束关系,有利于识别并行活动。

交互图:
描述对象间的交互关系。

顺序图显示对象之间的动态合作关系,它强调对象之间消息发送的顺序,同时显示对象之间的交互(也称时序图、序列图);

协作图描述对象间的协作关系,协作图跟顺序图相似,显示对象间的动态合作关系。除显示信息交换外,协作图还显示对象以及它们之间的关系。

如果强调时间和顺序,则使用顺序图;如果强调上下级关系,则选择协作图。

实现图:

构件图描述代码部件的物理结构及各部件之间的依赖关系。

配置图定义系统中软硬件的物理体系结构。

第七部分

设计原则

设计目标:

可扩展性(Extensibility):新功能易加入系统。

灵活性(Flexibility):允许代码修改平稳发生,不会涉及很多其他模块。

可插入性(Pluggability):容易将一个类换为另一个具有同样接口的类。

 设计原则

  1. 开闭原则OCP:Open-Closed Principle

2. 里氏替换原则LSP:Liskov Substitution Principle

3. 依赖倒转原则DIP:Dependency Inversion Principle

4. 接口隔离原则ISP:Interface Segregation Principle

5. 组合复用原则CRP:Compositoin Resuse Principle

6. 迪米特法则LoD:Law of Demeter

7.  单一职责原则(SRP)

开闭原则:

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开-闭法则认为应该试图去设计出永远也不需要改变的模块。

关键在于抽象化:可给系统定义一个一劳永逸,不再更改的抽象设计,此设计允许有无穷无尽的行为在实现层被实现。抽象层可以允许、支持所有扩展。

正在上传…重新上传取消

实现OCP: 做一个抽象类 ,接口等,使用抽象方法,虚函数。

里氏代换原则:(替换原则)

是指如果对每一个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都替换成o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

使用指向基类(超类)的引用的函数,必须能够在不知道具体派生类(子类)对象类型的情况下使用它们。一个软件如果使用的是一个父类的话,如果把该父类换成子类,它不能察觉出父类对象和子类对象的区别。也就是凡是父类适用的地方子类也适用。

1、Liskov替换法则(LSP)清楚地表明了IS A关系全部都是与行为有关的。

2、为了保持LSP,所有子类必须符合使用基类的client所期望的行为。

3、一个子类型不得具有比基类型更多的限制,可能这对于基类型来说是合法的,但是可能会因为违背子类型的其中一个额外限制,从而违背了LSP!

4、LSP保证一个子类总是能够被用在其基类可以出现的地方

正在上传…重新上传取消

引申含义:子类可以扩展父类的功能,但不能改变父类原有的功能。

1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

2、子类中可以增加自己特有的方法。

3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。

4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。

正方形继承长方形不符合里氏代换

依赖倒转原则:

抽象不应当依赖于细节,细节应当依赖于抽象。

指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。

设计原则 :

针对接口编程

要针对接口编程

不要针对实现编程

变量、参数、返回值等应声明为抽象类

不要继承非抽象类

不要重载父类的非抽象方法

不将变量声明为某个特定的具体类的实例对象,而让其遵从抽象类定义的接口。实现类仅实现接口,不添加方法。

组合复用原则:

优先使用(对象)组合,而非(类)继承

容器类仅能通过被包含对象的接口来对其进行访问。

尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。

继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的

Coad规则

仅当下列的所有标准被满足时,方可使用继承:

1、子类表达了“是一个…的特殊类型”,而非“是一个由…所扮演的角色”。is a

2、子类的一个实例永远不需要转化(transmute)为其它类的一个对象。

3、 子类是对其父类的职责(responsibility)进行扩展,而非重写或废除(nullify)。

4、子类没有对那些仅作为一个工具类(utility class)的功能进行扩展。

迪米特法则:

一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。

不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口(也就是定义中的“有限知识”)。

如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,那就放到本类中。

狭义:

如果两个类不必彼此通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可通过第三者转发这个调用。

朋友圈:

  1. 对象本身(this)
  2. 以参数形式传入当前对象方法的对象
  3. 当前对象创建的对象
  4. 当前实例变量直接引用的对象 (成员变量)
  5. 当前对象的实例变量如果是一个聚集,那么聚集内的元素也是朋友。(list与list内元素)

正在上传…重新上传取消

违反LKP例子:

stranger不是someone的朋友

改:friend有个方法直接调用operation3()

void Someone::Operation1(Friend friend){Stranger stranger = friend.provide();stranger.Operation3();}Stranger Friend::provide(){return stranger;}

广义:
控制信息过载,提高封装能力。

1. 创建弱耦合类,利于复用

2. 降低成员访问权限

3. 设计不变类

接口隔离原则 :

使用多个专门的接口比使用单一的总接口好。

一个类对另一个类的依赖性应建立在最小的接口上。

如果类的接口不是内聚的,就表示该类具有“胖”的接口。

ISP建议客户程序不应该看到它们作为单一的类存在。客户程序看到的应该是多个具有内聚接口的抽象基类。

正在上传…重新上传取消

单一职责原则:

即一个类只负责一项职责

不要存在多于一个导致类变更的原因。

职责扩散:就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。

例子:对于继承A的B,C,D有一个com()方法,突然要加一个E 继承A里面的com()方法不一样

方法一:把A拆开,TA1类管BCD,TA2类管E(单一职责原则满足)

方法二:修改com()方法原码,违背OCP,代码级别违背单一原则,修改简单

方法三:在A里加一个com2()专门处理E,方法级别违背单一原则,修改较简单,可以设计阈值,当这种方法大于阈值时,拆成多个类。

第八部分 设计模式

设计模式要素:

模式名称(pattern name) :一个助记名,它用一两个词来描述模式的问题、解决方案和效果。命名一个新的模式增加了我们的设计词汇。

问题(problem): 描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。

解决方案(solution): 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。

设计模式类型:

创建型:对象创建

结构型:处理类或对象组合

行为型:对类或对象怎样交互和怎样分配职责进行描述

创建模式:

简单工厂模式(封装可变性)

简单工厂模式是有一个工厂类根据传入的参量决定创建出哪一种产品类的实例。

有一个工厂类来实现工厂的行为。

工厂类(Creator)角色:该角色是工厂方法模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体类实现。

抽象产品(Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用接口或者抽象类实现。

具体产品(Concrete Product)角色:工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体类实现。

正在上传…重新上传取消

public class FruitGardener{public FruitIF factory(String which) throws BadFruitException{if (which.equalsIgnoreCase("apple")){ return new Apple(); }else if (which.equalsIgnoreCase("strawberry")){ return new Strawberry(); }else if (which.equalsIgnoreCase("grape")){ return new Grape(); }else{throw new BadFruitException("Bad fruit request");} } }

     工厂方法模式:

在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

正在上传…重新上传取消

Gardener是一个抽象工厂

下面蓝线表示消息的传递

正在上传…重新上传取消

抽象工厂(Abstract Factory)模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态  可以简单理解为一个工厂,生产许多产品。
抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

产品等级结构:

产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

产品族:

在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。

在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。

正在上传…重新上传取消

单例(Singleton)模式

单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

饿汉式单例类

使用static 标识全局唯一,当类初始化时,初始化单例。

由于构造子是私有的,因此,此类不能被继承。

public class EagerSingleton{private static final EagerSingleton m_instance =new EagerSingleton();/*私有的默认构造子*/private EagerSingleton() { }/* 静态工厂方法*/public static EagerSingleton getInstance(){return m_instance;}

懒汉式单例类

static 第一次 get单例对象时获取,记得加锁。

由于构造子是私有的,因此,此类不能被继承。

饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的,在饿汉式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲,这个比懒汉式单例类稍差些。

public class LazySingleton {private LazySingleton() { }public static LazySingleton getInstance(){if (m_instance == null){file://More than one thread might be here!!!synchronized(LazySingleton.class){if (m_instance == null){m_instance = new LazySingleton();} } }return m_instance;}private static LazySingleton m_instance = null;}

生成器模式:

定义:封装一个复杂对象构造过程,并允许按步骤构造。

定义解释: 我们可以将生成器模式理解为,假设我们有一个对象需要建立,这个对象是由多个组件(Component)组合而成,每个组件的建立都比较复杂,但运用组件来建立所需的对象非常简单,所以我们就可以将构建复杂组件的步骤与运用组件构建对象分离,使用builder模式可以建立。

原型(Prototype)模式

定义:通过复制现有实例来创建新的实例,无需知道相应类的信息。

简单地理解,其实就是当需要创建一个指定的对象时,我们刚好有一个这样的对象,但是又不能直接使用,我会clone一个一毛一样的新对象来使用;基本上这就是原型模式。关键字:Clone。

原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。

(1)简单形式

(2)登记形式

这两种表现形式仅仅是原型模式的不同实现。

结构模式

描述如何将类和对象组合成一个更大的结构

可以分为类模式和对象模式

类模式采用继承机制来组合接口和实现

对象模式描述了如何对一些对象进行组合,实现新功能的一些方法

适配器模式

将一个类的接口转换成客户希望的另外一个接口。

Adapter模式使得原本由于接口不兼容而不能一起的那些类可以一起工作。

类适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。

对象适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。

接口适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

Adapter模式也叫做包装器Wrapper。

正在上传…重新上传取消

代理模式

为其他对象提供一种代理以控制对这个对象的访问。

正在上传…重新上传取消

Decorator模式

动态地给一个对象添加一些额外的职责,别名也叫Wrapper

Decorator必须和要包装的的对象具有相同的接口

有时我们希望给某个对象而不是整个类添加一些功能。

它针对的是整个类,但Decorator不使用继承,所以它只是针对单个对象实例,进行功能的扩展,并且可以在运行时动态地灵活地对功能进行组装

装饰者模式结构图与代码示例

1.Component(被装饰对象的基类)

定义一个对象接口,可以给这些对象动态地添加职责。

2.ConcreteComponent(具体被装饰对象)

定义一个对象,可以给这个对象添加一些职责。

3.Decorator(装饰者抽象类)

维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。

4.ConcreteDecorator(具体装饰者)

具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。

正在上传…重新上传取消

Bridge模式

定义:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性。

把抽象部分和行为部分分离,使它们都能独立变化

将抽象和行为划分开来

各自独立

但能动态的结合

将抽象化与实现化进行脱藕

正在上传…重新上传取消

FLYWEIGHT(享元):

运用共享技术有效地支持大量细粒度的对象

1、Flyweight (享元抽象类):一般是接口或者抽象类,定义了享元类的公共方法。这些方法可以分享内部状态的数据,也可以调用这些方法修改外部状态。

2、ConcreteFlyweight(具体享元类):具体享元类实现了抽象享元类的方法,为享元对象开辟了内存空间来保存享元对象的内部数据,同时可以通过和单例模式结合只创建一个享元对象。

3、FlyweightFactory(享元工厂类):享元工厂类创建并且管理享元类,享元工厂类针对享元类来进行编程,通过提供一个享元池来进行享元对象的管理。一般享元池设计成键值对,或者其他的存储结构来存储。当客户端进行享元对象的请求时,如果享元池中有对应的享元对象则直接返回对应的对象,否则工厂类创建对应的享元对象并保存到享元池。

正在上传…重新上传取消

FACADE(外观):

为子系统中的一组接口提供一个一致的界面, F a c a d e模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观(f a c a d e)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。

正在上传…重新上传取消

行为型模式

行为类模式使用继承机制在类间分派行为,行为对象模式是复合对象。

策略模式:

定义: 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

正在上传…重新上传取消

观察者模式:

定义对象间的一种一对多的依赖关系,

当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并被自动更新。

正在上传…重新上传取消责任链模式:

定义:如果有多个对象有机会处理请求,责任链可使请求的发送者和接受者解耦,请求沿着责任链传递,直到有一个对象处理了它为止。

主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

命令模式

定义:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适

状态模式

定义: 在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

简单理解,一个拥有状态的context对象,在不同的状态下,其行为会发生改变。

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

山东大学面向对象笔记 整理相关推荐

  1. JavaScript之面向对象与原型笔记整理--------创建对象之原型(2)

    4.原型 每个函数都有一个prototype属性,这个属性是一个对象,用途是包含可以由特定类型的所有实例共享的属性和方法. 逻辑上可以这么理解:prototype通过调用构造函数而创建的那个对象的原型 ...

  2. java反射 pdf_java反射学习笔记整理.pdf

    java反射学习笔记整理.pdf 还剩 15页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,很抱歉,此页已超出免费预览范围啦! 如果喜欢就下载吧,价低环保! 内容要点: Java 反射笔记 ...

  3. 【笔记整理】图解设计模式 | 第16章 Mediator模式(只有一个仲裁者)

    [笔记整理]图解设计模式 | 导航 定义 组员向仲裁者报告,仲裁者向组员下达指示. 当发生麻烦事情的时候,通知仲裁者:当发生涉及全体组员的事情时,也通知仲裁者. 当仲裁者下达指示时,组员会立即执行.团 ...

  4. 【笔记】设计模式 | 5种设计模式笔记整理

    跟着b站的设计模式教程学的,以下是目前学习了的5种设计模式的笔记整理 设计模式简介 软件设计的现状:由于客户需求等原因需要频繁的变更软件内部的代码.所以能否设计出复用性尽可能高的程序以解决软件设计的复 ...

  5. 慕课Java第三季学习及笔记整理

    学习网址及截图和部分图片来源:https://www.imooc.com/learn/110 慕课Java第三季学习及笔记整理 一.异常与异常处理 1-1 java异常简介 概念 异常体系结构 1-2 ...

  6. 2021/06/29计算机视觉期末复习笔记整理

    计算机视觉期末复习笔记整理 引言 我的复习参考 期末考试考题回忆 PPT对应中文笔记整理 参考的几篇博客的笔记 引言 刚结束可能是我学生时代最后一场考试了,orz热乎着,记录一下. 这门课是学校新开的 ...

  7. javascript学习笔记整理

    javascript从零到精通笔记整理 js写在哪 - css写在哪- 内联(行内):属性形式:style="样式属性:样式属性值"- 内部:style双标签,包裹css样式- 外 ...

  8. (超详细笔记整理)动力节点_老杜 | JavaSE零基础 :P329(方法) - P479

    JAVA基础学习 第二篇文章的连接: (超详细笔记整理)动力节点_老杜 | JavaSE进阶 [P486之后]. 文章目录 JAVA基础学习 方法 Java的主要内存空间 栈数据结构 **栈数据结构: ...

  9. Java笔记整理五(Iterator接口,泛型,常见数据结构(栈,队列,数组,链表,红黑树,集合),jdk新特性,异常,多线程,Lambda表达式)

    Java笔记整理五 1.1Iterator接口 Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象 ...

最新文章

  1. 利用openssh实现chroot监牢
  2. python之tkinter图形界面
  3. 【AutoML】强化学习如何用于模型蒸馏?
  4. 高一计算机专业用平板电脑,高中生需不需要平板电脑或者笔记本电脑?
  5. 让 AI 为你写代码 - 体验 Github Copilot
  6. dj鲜生-38-项目上线简介-从本地小项目到云服务的调试
  7. mysql server出现_查询各阶段时,一旦mysql server出现各种故障下的表现形式
  8. React.createClass和extends Component的区别
  9. 取消IE“已限制此网页运行可以访问计算机的脚本
  10. Hadoop集群常用命令
  11. 网联下发42号文督促生产测试 银行代扣通道都将关闭 协议支付
  12. 第一章:网络信息安全概述精讲笔记
  13. TP5.1使用 GatewayWorker 进行 socket 通讯
  14. 强化学习的方法总结与分类
  15. 构建基于 MCU 安全物联网系统
  16. [Java]String类基础知识与常用方法总结
  17. 天道酬勤,记春招之路(完美世界,360,腾讯IEG,网易雷火)
  18. 深度学习实现安全帽佩戴的检测
  19. 技术支撑团队技术支持工程师的技能要求
  20. HDLBits(4) Procedures合集

热门文章

  1. Unity 5 物理
  2. 2018年一季度全球服务器市场排名定了 谁喜谁忧?
  3. Breast cancer detection in rotational thermography images using texture feature
  4. win7计算机左边增加桌面,技术帖,win7如何在任务栏左下角添加“显示桌面”图标。...
  5. win7计算机里桌面菜单没有反应,win7系统鼠标右键点击桌面没反应怎么办 鼠标右键没反应解决方法...
  6. 互联网智能手机资讯博览
  7. 球状空心介孔硫化铋/二氧化硅纳米微球/全无机铯铅卤化物钙钛矿纳米晶修饰二氧化硅微球相关制备
  8. ToF的多径干扰抑制分析----ToF技术专题系列(四)
  9. 武忠祥每日一题-第1题
  10. 【武忠祥高等数学基础课笔记】常微分方程