如果把修习软件开发当作练武功修炼的话,那么可以分为招式和内功
每一位软件开发人员也都希望成为一名兼具淋漓招式和深厚内功的“上乘”,软件开发工程师,二对设计模式的学习与领悟会让你“内功”大增,再结合你日益纯熟的“招式”,你的软件开发“功力”一定会有一个新的境界,
设计模式定义
设计模式是在特定环境下人们解决某类重复出现的问题的一套成功有效的解决方案.
设计模式由GoF四人组
引入软件工程领域,这就是软件设计模式的诞生,软件模式是将模式的一般概念应用软件开发领域,即软件开发的总指导思路与参照样板,软件模式并非仅限于设计模式,还包括架构模式,分析模式,和过程模式等。
软件模式与具体的应用领域无关,也就是说无论你从事的是移动还是桌面开发,还是嵌入式,都可以使用软件模式,无论使用那种面向对象语言都需要了解软件设计模式。
软件设计模式的概念
是一套被反复使用、多数人知晓的、经过分类编目的,代码设计经验的总结,使用设计模式是为了可重用性代码,让代码更容易被他人理解并且保持代码的可靠性。总之,在一定环境下,用固定套路解决问题。
GoF提出的模式有23个,总包括:
创建型模式
(6):如何创建对象
结构型模式
(7):如何实现类和对象的组合
行为型模式
(11):类或对象怎样交互以及怎样分配职责
当然,这23之外有一个“简单工厂模式”,不属于GoF23中设计模式,但大部分设计模式书籍都会对它进行介绍。
设计模式种类=GoF种类+“简单工厂模式” = 24种
高端的讲,作用大了去了,对于初学者,学习设计模式有助于更深一次理解面向对象,让你知道:
如何将代码分散在不同类中
为什么有接口
何谓针对抽象编程
何时不应该使用继承
如何不修改源代码增加新功能
更好的阅读和理解现有库和其他系统中的源代码
学习设计模式让你早点脱离“菜鸟期”!
学习基础:多态
【继承,虚函数重写,父类指针指向子类对象】
初学者:积极累积案例,不能硬背
初级开发者:多思考,梳理,总结,尊重事物的规律,注意临界点突破
中级开发者:合适的开发环境,寻找合适的设计模式来解决问题,多运用,对经典组合设计模式的大量,自由的运用,不断的追求
对于面向对象软件系统而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个系统的可维护性和可复用性是面向对象以设计原则为基础的,每一个原则都蕴含一些面性对象设计的思想,可以从不同角度提升一个软件结构的设计水平
面向对象设计原则为支持可维护性可复用性二诞生,这些原则蕴含在很多设计模式中,他们是从许多设计方案中总结出来的指导性原则,面向对象设计原则也是我们用于评价一个设计模式的重要性指标之一
原则目的:
高内聚
:目标明确单一,一个main只干一件事,出了问题自行修改main,
低耦合
,模块尽量少的跟其他模块交互,否则出了问题很难维护
类的职责单一,对外只提供一个工能,而引起类变化的原因都应该只有一个
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
/*如果多人修改hi出问题
class Cloths
{
public:
void Shopping()
{
cout << "休闲服装" << endl;
}
void working()
{
cout << "正式服装" << endl;
}
};
*/
//改进
class Clothwork
{
public:
void style()
{
cout << "正式服装"<< endl;
}
};
class Clothshopp
{
public:
void style()
{
cout << "休闲服装" << endl;
}
};
int main()
{
/*Cloths c1;
c1.Shopping();
c1.working();
*/
Clothshopp c2;
c2.style();
Clothwork c3;
c3.style();
system("pause");
return 0;
}
//修改一个方法,会影响到其他方法,违反单一职责原则,应该将其分离出来
类的改动是通过增加代码进行的,而不是修改源代码
#define _CRT_SECURE_NO_WARNINGS 1
#include
using namespace std;
/*
class bank
{
public:
void save()
{
cout << "存款"<
//抽象 业务员类
class abstractbank
{
public:
virtual void work() = 0; //抽象类接口
};
//存款
class save :public abstractbank
{
public:
virtual void work()
{
cout << "存款"<< endl;
}
};
//支付
class pay :public abstractbank
{
public:
virtual void work()
{
cout <<"支付" << endl;
}
};
//转账
class transfer :public abstractbank
{
public:
virtual void work()
{
cout << "转账"<< endl;
}
};
//添加基金,只需要在继承基类,实现业务虚函数即可
class add : public abstractbank
{
public:
virtual void work()
{
cout << "基金" << endl;
}
};
int main()
{
//产生多态三条件:继承,重写,父类指针指向子类对象
abstractbank *sb = new save;
sb->work();
delete sb;
abstractbank *sb = new pay;
sb->work();
delete sb;
system("pause");
return 0;
}
//这样,如果我们给银行添加业务,无须修改类中代码,而是通过拓展添加类的方式搞定,实际利用了多态的特性,这样就符合了开闭原则
任何抽象类出现的地方都可以用它的实现类进行替换,实际就是虚拟机制,语言级别实现面向对象工程
建议多用多态
依赖于抽像(接口),不要依赖具体的实现(类),也就是针对接口编程。
#define _CRT_SECURE_NO_WARNINGS 1
#include
using namespace std;
/*class benchi
{
public:
void run()
{
cout << "奔驰启动" << endl;
}
};
class bm
{
public:
void run()
{
cout << "宝马启动" << endl;
}
};
class zhangsan
{
public:
void drivebenchi(benchi* b)
{
b->run;
}
void drivebm(bm* b)
{
b->run;
}
};*/
//改进:如果人多了,车类型多,那么就会很乱,复杂,所以可以抽喜抽喜car,司机类
//抽像层
class Driver
{
public:
virtual void drive(Car* car) = 0;
};
class Car
{
public:
virtual void run() = 0;
};
//实现层
class zhangsan:public Driver
{
public:
virtual void drive(Car* car)
{
cout << "zhangsan" << endl;
car->run;
}
};
class lisi:public Driver
{
public:
virtual void drive(Car* car)
{
cout << "lisi" << endl;
car->run;
}
};
class benchi :public Car
{
public:
virtual void run()
{
cout << "benchi" << endl;
}
};
class bm :public Car
{
public:
virtual void run()
{
cout << "bm" << endl;
}
};
int main()
{
/*//张三开奔驰
benchi *b = new benchi;
zhangsan *z = new zhangsan;
z->drivebenchi(b);
//张三开宝马
bm *m= new bm;
z->drivebm(m);
*/
//优点:运用的类少
//逻辑层与实现层通过抽象层隔离叫做解耦合
//zhangsan开奔驰
Car *b = new benchi;
Driver *d = new zhangsan;
d->drive(b);
delete(b);
delete(d);
//lisi开宝马
Car *b = new bm;
Driver *d = new lisi;
delete(b);
delete(d);
d->drive(b);
system("pause");
return 0;
}
传统的设计模式通常是自顶向下逐级依赖,这样底层模块,中间层模块和高层模块的耦合极高,若改动其中一个,很容易导致全面积修改,非常麻烦,那么依赖倒转原则利用多态先天特性,对中间层进行依赖,这样底层与高层进行哦解耦合。
电脑厂需要硬盘,cpu,内存,硬盘,cpu,内存第三方厂商均可以进行对接,但是电脑生产公司只是对外提供抽象中间层接口,第三方厂商想要加入只需要面向这个抽喜类实现各自的实例就可以了。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
//抽象层
class CPU
{
public:
virtual void caculate() = 0;
};
class Card
{
public:
virtual void dispaly() = 0;
};
class Memory
{
public:
virtual void storage() = 0;
};
//架构层 (包含所有抽像类)
//架构层与实现层 解耦合
class computer
{
public:
computer(CPU* cpu, Card* card, Memory* mermory)
{
this->cpu = cpu;
this->card = card;
this->memory = memory;
}
//高层业务逻辑,不关心哪个厂商,只是对抽象层的每个硬件任务
void work()
{
cpu->caculate();
card->dispaly();
memory->storage();
}
private:
CPU* cpu;
Card* card;
Memory* memory;
};
//实现层 (只需要依赖中间抽象层,只需要实现抽象层的方法)
class interCPU:public CPU
{
public:
void caculate()
{
cout <<"caculaet"<<endl;
}
};
class interCard:public Card
{
public:
void display()
{
cout << "display" << endl;
}
};
class interMemory:public Memory
{
public:
void storage()
{
cout << "storage" << endl;
}
};
//高业务层
int main()
{
CPU* cpu = new interCPU;
Card* card = new interCard;
Memory* mem = new interMemory;
computer* com = new computer(cpu,card,mem);
com->work();
delete(cpu);
delete(card);
delete(mem);
delete(com);
system("pause");
return 0;
}
不应该强迫用户的程序依赖他们不需要的接口方法,一个接口应该只是提供一种对外功能,不应该吧所有操作都封装到一个接口去,
如果使用继承,会导致父类的任何交换都可能影响到子类的行为,如果使用对象组合,就降低了这种依赖关系,对于继承与组合优先使用组合。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
class Cat
{
public:
void sleep()
{
cout << "睡觉"<< endl;
}
};
//创建一个新的猫,且增加一个功能,即能睡觉又能吃东西
//如果Cat有很多父类,cat的父类与AddCat高耦合,复杂度高
//通过继承完成
class AddCat:public Cat
{
public:
void eat()
{
cout << "吃饭"<< endl;
sleep();
}
};
//使用组合方式添加吃东西
//使用组合降低Add2Cat与Cat耦合,跟Cat父类没有任何关系,
//只跟Cat与slepp有关系
class Add2Cat
{
public:
Add2Cat(Cat* cat)
{
this->cat = cat;
}
void eat(Cat* cat)
{
cout <<"吃饭" << endl;
cat->sleep();
}
private:
Cat* cat;
};
int main()
{
Cat c;
c.sleep();
AddCat ac;
ac.eat();
Add2Cat ac(&c);
ac.eat();
system("pause");
return 0;
}
一个对象应尽可能少的了解其他对象,从而降低各个对象之间的耦合度,提高系统的可维护性,例如一个程序中,各个模块之间相互调用,通常会提供一个统一的接口,来实现,这样其他模块不需要了解另一个模块的内部实现原理,当一个模块的内部的实现发生改变时,不会影响其他模块的使用(黑盒原理)
【类比种类就是这个原理】