1.面向对象设计的七大原则
面向对象设计的七大基本设计原则:
- 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。所以一个类应当只负责一项职责
理解:不求面面俱到,只做一件事 - 开放封闭原则(OCP):对于扩展是开放的,对于更改是封闭的。就是说软件实体(类模块,函数等等)应该可以扩展,但是不能修改。软件开发和维护过程中代码的修改是危险的,应该避免。实现开放封闭原则的关键是抽象。(声明抽象基类)理解:变化也是可以预测的,变化也需要被管理。
#include<iostream>
#include<memory>
//声明一个抽象基类
class Banker
{
private:
protected:
public:
virtual void DoThing() = 0;
virtual ~Banker() {}
};
class SaveBanker:public Banker
{
public:
virtual inline void DoThing()
{
std::cout<<"存钱"<<std::endl;
}
private:
protected:
};
class TransferBanker:public Banker
{
private:
protected:
public:
virtual inline void DoThing()
{
std::cout<<"转钱"<<std::endl;
}
};
void ObjPlay( Banker * ptr)
{
ptr->DoThing();
}
int main()
{
//SaveBanker banker1;
//TransferBanker banker2;
//ObjPlay(&banker1);
//ObjPlay(&banker2);
std::auto_ptr<Banker>savebanker(new SaveBanker());
ObjPlay(savebanker.get());
std::auto_ptr<Banker>transferbanker(new TransferBanker());
ObjPlay(transferbanker.get());
return 0;
}
//以上案例中,可以通过抽象基类派生子类,在子类中重写虚函数方法来扩展功能
- 依赖倒置原则:高层模块不因该依赖底层模块,两个都应该依赖抽象;抽象不应该依赖细节,细节因该依赖抽象。依赖倒置原则是开放封闭原则实现的手段,是抽象的最好规范。要针对接口编程,不要针对功能和过程编程。理解:电厂根据电线和变压器来设计电压强度,而不是根据手机等用电器来设计电压强度。
#include<iostream>
#include<memory>
using namespace std;
class HardDisk
{
private:
public:
virtual void Work() = 0;
};
class Cpu
{
private:
public:
virtual void Work() = 0;
};
class Memory
{
private:
public:
virtual void Work() = 0;
};
class XDHardDisk:public HardDisk
{
public:
virtual inline void Work()
{
cout<<"The harddisk begin work"<<endl;
}
};
class IntelCpu:public Cpu
{
public:
virtual inline void Work()
{
cout<<"The cpu begin work"<<endl;
}
};
class SXMemory: public Memory
{
public:
virtual inline void Work()
{
cout<<"The memory begin work"<<endl;
}
};
class Computer
{
private:
HardDisk * harddisk;
Cpu * cpu;
Memory * memo;
public:
void DoThing()const;
explicit Computer( HardDisk * my_harddisk, Cpu * my_cpu, Memory * my_memory)
:harddisk(my_harddisk),cpu(my_cpu),memo(my_memory){}
};
void Computer::DoThing()const
{
harddisk->Work();
cpu->Work();
memo->Work();
}
int main()
{
auto_ptr<HardDisk>HDptr(new XDHardDisk);
auto_ptr<Cpu>CPUptr(new IntelCpu);
auto_ptr<Memory>Meptr(new SXMemory);
//Computer object(HDptr.get(),CPUptr.get(),Meptr.get());
//object.DoThing();
auto_ptr<Computer>object(new Computer(HDptr.get(),CPUptr.get(),Meptr.get()));
object ->DoThing();
return 0;
}
//在以上案例中,高层模块(computer类)和底层模块类(如XDHardDisk类)都依赖于抽象类
//如(HardDisk类)。细节(如XDHardDisk类)实现依赖于抽象类(如HardDisk类)。
- 里氏代换原则:子类型必须能够替换掉他们的父类型。也就是一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,父类替换成子类后,程序的行为不会发生变化。只有当子类可以替换掉父类,软件的功能没有受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。 理解:人可以代表动物,动物不可以代表人。
#include<iostream>
using namespace std;
//客户抽象基类
class Customer
{
public:
//接受邮件
virtual void Receive() = 0;
virtual ~Customer()
{
}
};
class VIPCustomer: public Customer
{
public:
virtual void Receive()
{
cout<<"Vip customer has received message"<<endl;
}
};
class CommonCustomer: public Customer
{
public:
virtual void Receive()
{
cout<<"Common customer has received message"<<endl;
}
};
class EmailSender
{
public:
//发送邮件
void Send()
{
if(customer)
{
customer ->Receive();
}
}
void SetCustomer(Customer * customer)
{
this -> customer = customer;
}
EmailSender():customer(NULL){}
private:
Customer * customer;
};
int main()
{
//这里定义局部变量customer1或者customer2使用了里氏代换原则。
//这里引用基类的地方也可以透明的使用子类的对象。因此里氏代换
//原则是实现开闭原则的重要方式之一。
Customer * customer1 = NULL;
Customer * customer2 = NULL;
EmailSender * sender =NULL;
customer1 = new VIPCustomer();
customer2 = new CommonCustomer();
sender = new EmailSender();
sender ->SetCustomer(customer1);
sender ->Send();
sender ->SetCustomer(customer2);
sender ->Send();
delete customer1;
delete customer2;
delete sender;
return 0;
}
- 迪米特法则:如果两个类不能彼此直接通信,那么两个类不应该发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法时,可以通过第三者转发这个调用。 迪米特法则的思想强调了类之间的松耦合,类之间的耦合越弱,越有利于代码复用。一个处在弱耦合的类被修改,不会对有关系的类造成波及。
- 接口隔离法则:使用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当建立在最小接口上的。如果没有关系的接口合并在一起,将会形成一个臃肿的大接口。
- 组合复用原则:尽量使用对象组合(类中内嵌对象),而不是继承来达到复用的目的。