1.面向对象设计的七大原则

面向对象设计的七大基本设计原则:

  1. 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。所以一个类应当只负责一项职责
    理解:不求面面俱到,只做一件事
  2. 开放封闭原则(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;
}
//以上案例中,可以通过抽象基类派生子类,在子类中重写虚函数方法来扩展功能
  1. 依赖倒置原则:高层模块不因该依赖底层模块,两个都应该依赖抽象;抽象不应该依赖细节,细节因该依赖抽象。依赖倒置原则是开放封闭原则实现的手段,是抽象的最好规范。要针对接口编程,不要针对功能和过程编程。理解:电厂根据电线和变压器来设计电压强度,而不是根据手机等用电器来设计电压强度。
#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类)。
  1. 里氏代换原则:子类型必须能够替换掉他们的父类型。也就是一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,父类替换成子类后,程序的行为不会发生变化。只有当子类可以替换掉父类,软件的功能没有受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。 理解:人可以代表动物,动物不可以代表人。
#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;
}
  1. 迪米特法则:如果两个类不能彼此直接通信,那么两个类不应该发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法时,可以通过第三者转发这个调用。 迪米特法则的思想强调了类之间的松耦合,类之间的耦合越弱,越有利于代码复用。一个处在弱耦合的类被修改,不会对有关系的类造成波及。
  2. 接口隔离法则:使用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当建立在最小接口上的。如果没有关系的接口合并在一起,将会形成一个臃肿的大接口。
  3. 组合复用原则:尽量使用对象组合(类中内嵌对象),而不是继承来达到复用的目的。