设计模式的学习

OOP的核心思想:

 

封装(Encapsulation).

继承(inheritance).

多态(polymorphism).

 

什么是类?

概念层某些责任的抽象.

规格层一系列可以被其他对象使用的接口.

语言层封装了代码和数据.

 

 

软件设计原则:

针对接口编程,而不是针对实现.

不要滥用继承,理清继承和组合的关系.

[继承处理类之间的静态关系,组合处理对象间的动态关系]

分清层次,封装变化点.

 

类设计原则:

 

单一职责原则(SRP-Single Responsibility Principle).

一个类应该只有一个引起它变化的原因.

[如果一个类既负责一个类的显示,又表示一个类的存储,当显示需求变化时或者存储变化时都要修改这同一个类. 不过, 虽然SRP要求对每一个可能变化的职责都进行分开固然是正确的,但是这个变化一定要是现实中“真的可能”发生的。我们要专注于那些有较大可能发生变化的地方,而忽略那些不太可能变化或变化概率极小的细枝末节。比如说,你的数据访问逻辑是固定的,而中途变化数据库的可能也不大,因此,就没有必要把数据访问单独出来。一句话,不能为了“Everything is possible”,就把类结构设计的异常复杂。]

 

开放封闭原则(OCP-The Open-Closed Principle).

类可以扩展,但不可修改(对扩展开放,对修改封闭)[继承,让模块依赖于一个固定的抽象体,这个抽象体是不可以修改的;同时,通过这个抽象体派生,我们就可以扩展此模块的行为功能.关键是对抽象体的定义.]

 

Liskow替换原则(LSP -Liskov Substitution Principle)

子类必须可以替换基类.

[子类必须能够完成父类定义的所有任务]

 

依赖倒置原则(DIP-Dependency-Inversion Principles).

高层模块不应该依赖低层模块,二者应该依赖于抽象.

抽象不应该依赖于实现,实现应该依赖于抽象.

 

接口隔离原则(ISP-Interface Segregation Principle ).

不应该强迫客户程序依赖于它们不用的方法,一个类对另外一个类的依赖性应当是建立在最小的接口上(不要把不相关的放在同一个接口中).

 

 

什么是设计模式

描述软件设计过程中某一类常见问题的一般性解决方案.

 模式是用来对应变化的,不要为了用模式而用模式.

 

模式分类:

创建型(creational):负责对象创建.

结构型(structural): 处理类于对象的组合.

行为型(behavioral).:类于对象交互中的职责分配.

字符串的旋转

一个题目:给定字符串,要求把字符串前面的若干字符移动到字符串的尾部,例如:字符串“abcdef”,前三个字符’a’,’b’,’c’移动到字符串的尾部,字符串变成”defabc”,用函数实现。

一般最先想到的办法是将需要移动的字符一个个的移动到字符串的尾部(开始的时候,我这个都没有想到–!,基础差到无边无际)

一:定义一个指向字符串的指针s,字符长度为n书写函数。

void moveone(char *s,int n)

{

char t =s [0];

int i = 0;

for (i  =1 ;i < n; i++){

s[i – 1] = s[i];

}

s[n -1] = t;

}

然后调用m次moveone函数,使得字符串开头的m个字符移动到字符串尾部:

void  formoveone( char *s,int n, int m)

{

while(m–){

moveone(s,n);

}

}

这样就完成了将若干字符移动到字符串尾部了。但是这种方法对于长度为n的字符串来说,移动m个字符,一共进行了m*n此操作,并且用了一个字符保存变量,所以时间复杂度为(m*n),空间复杂度为O(1)。手动执行了一把程序,运行时间还是比较长。

进一步思考:如何降低时间复杂度。

如果把需要移动的字符和不需要移动的字符分成两部分,比如分为abc,def,分别反转,最后对整个字符串进行反转,这样也可以达到移动字符串的目的。反转第一部分abc,为cba,在反转def为fed,整体字符串变为cbafed,进而继续反转整个字符串得到defabc,就实现了字符串的反转。

解法:

void  fun( char *s ,int from,int to)

{

while(from < to ){

char t = s[from];

s[from ++] = s[to];

s[to–]=t;       }

}

void formovestring(char *s, int n,int m)

{

m%=n;

fun(s,0,m-1);

fun(s,m,n-1);

fun(s,0,n-1);

}

再来看代码,时间复杂度为O(n),空间复杂度为O(1);俗称”三步反转“得到结果。

该题目以及步骤均来自July《编程之法》