设计模式学习总结:(1)面向对象五大基本原则

 

最近学习了李建忠老师设计模式教程,感受有一种豁然开朗的感受。数据库

"每个模式描述了在咱们周围不断重复发生变化的问题,以及该问题的解决方案的核心。这样,你就能一次又一次的使用该方案而没必要重复的劳动"——christopher alexander编程

固然,设计模式的有本很著名的书,常考教程:设计模式

书名:设计模式:可复用面向对象软件的基础学习

 

固然,我不是推销书的。主要是书名很明确的给出了,软件设计模式中使用的手法,经常使用就是面向对象,确实,在我第一次听到面向对象的时候,个人理解是彻底不懂,在个人二次学习面向对象的时候,个人理解是封装,继承,多态。而到如今,我以为,咱们的最终目的,仍是编写可复用,可扩展,便于维护的软件。固然,如何把面向对象的特性运用到极致,我想还得深刻去理解设计模式,否则,不少时候,即便咱们用了面向对象语言编程,每每出现拔苗助长的效果。spa

 

这里先给出面向对象五大基本原则:设计

(DIP)依赖倒置原则:3d

  1. 高层模块(稳定)不该该依赖于底层模块(变化),两者都应该依赖于抽象(稳定)。code

  2. 抽象(稳定)不该该依赖于实现细节(变化),实现细节依赖于抽象(稳定)。对象

  个人理解:总结为,稳定的东西不该该依赖于变化的东西。在面向对象设计过程当中,可能有时候,我会把一些具体实现依赖另一些具体实现,可是咱们知道,具体实现是容易变化的,若是依赖的实现发现变化,意味着上层也将发生变化。这里的变化,不是说具体的逻辑变更,而是接口变更,简单的说就是,面向对象应该面向抽象接口来实现,而不是面向具体的逻辑,这个抽象接口应该是十分稳定的,依赖于一个稳定的接口的好处,就是,咱们具体实现和耦合性会比较低。这意味着咱们须要很敏感的发现系统的稳定点和变化点,将稳定点变成抽象接口,把变化点变成扩展实现。blog

我本身想了一个坏栗子,不知道合不合适:

class Waiter //服务生
{


}

class Cater //计算员
{

}

class Guard //保安
{

}
class Bank
{
public:
  vector<Waiter> waiterList;
  vector<Cater> caterList;
  vector<Guard> guardList;
  
protect:
  void doWork();  
}

void Bank::doWord()
{
for(auto a in waiterList)
{
a.doWord();
}
for(auto a in caterList)
{
a.doWord();
}
for(auto a in guardList)
{
a.doWord();
}

做为伪代码,随意看看吧,我想意思很简单,首先有个员工文件,里面我定义了三种员工,而后银行定义了员工的LIst,固然,实际可能还须要添加员工犯法,dowork方法用来让他的员工工做,代码冗余问题虽然还能够解决,可是,最大的问题是,你应该发现,员工种类咱们假设是须要扩展的,这种方式,就是具体依赖于具体。你能够假设若是如今多了一种员工,叫作数据库管理员,那么你对于上面的代码应该作那些修改。我想你应该,写一个类,而后,在银行类里面,添加一个数据库管理员list对象,最后,还要在员工在工做里面在添加方法。是否是很不利。

我想,好的方式是这样:

 

class Staff
{
public:
    void doWork()=0;
    void ~Staff()
    {}
}

class Waiter:public Staff //服务生
{
public:
    void doWork();

}

class Cater:public Staff //计算员
{
    void doWork();
}

class Guard:public Staff //保安
{
    void doWork();
}

 

 

class Bank
{
public:
 vector<Staff *> stafflList;
  
protect:
  void doWork();  
}

void Bank::doWord()
{
for(auto a in staffList)
{
   a.doWork();
}

 

 你如今能够想象下,若是这种状况下,老板让你添加一种新的员工,叫作数据库,管理员,那么是否是方便,你只须要,在写一个类,而后继承抽象基类staff便可。这也就是面向抽象基础编程。

开放封闭原则(OCP)

  1. 对扩展开放,对更改封闭。

  2. 类模块应该可扩展的,可是不可更改。

个人理解:开放封闭原则,是最为重要的设计原则。然后面的Liskov替换原则和合成/聚合复用原则为开放封闭原则的实现提供保证。

我这里无耻的引用百度百科的例子:

class BusyBankStaff
{
    private BankProcess bankProc = new BankProcess();
// 定义银行员工的业务操做
    public void HandleProcess(Client client)
    {
        switch (client.ClientType)
        {
            case "存款用户":
                bankProc.Deposit();
               break;
             case "转帐用户":
                bankProc.Transfer();
               break;
             case "取款户":
                bankProc.DrawMoney();
                break;
        }
    }
}

其实这代码跟第一个原则差很少,对扩展开发怎么理解,这段代码问题主要在于,若是有新的业务出现,那么扩展,将在switch中进行修改,实际上违背了对修改封闭的原则,也就是说,若是出现新的业务,咱们须要的是扩展,而不是修改以前的类。那么好的实现方法能够是这样的:

class IBankProcess
{
    virtual void Process()=0;
}

<-接口基类

class DepositProcess : IBankProcess
{
//IBankProcess Members

    public void :
    Process()
    {
    // 办理存款业务
    }
}
class TransferProcess : IBankProcess
{
//IBankProcess Members

    public :
    void Process()
    {
    // 办理转帐业务

    }
}
class DrawMoneyProcess : IBankProcess
{
//IBankProcess Members

    public :

    void Process()
    {
    // 办理取款业务 
    }
}

<-不一样业务

 

class EasyBankStaff
{
    private :
        IBankProcess *bankProc = NULL;
    public :
    void HandleProcess(Client client)
    {
         bankProc = client.CreateProcess();
         bankProc.Process();
    }
}

<-用户切换

 

class BankProcess
{
    public:
    void Main()
    {
        EasyBankStaff bankStaff = new EasyBankStaff();
        bankStaff.HandleProcess(new Client("转帐用户"));
    }
}

处理业务,就这个方法而言,对于银行业务扩展,咱们只须要定义新的类,这叫对扩展开放,而不须要修改原先类的代码,这叫对修改封闭。这样一个原则,是否是很像一个衡量标准呢。

 

单一职责原则(SRP)

  1. 一个类应该仅有一个引发它变化的缘由。

  2. 变化的方向隐含着类的责任。

这是相对比较好理解的吧,"若是一个类承担的职责过多,就等于把这些职责耦合在一块儿了。一个职责的变化可能会削弱或者抑制这个类完成其余职责的能力。这种耦合会致使脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而若是想要避免这种现象的发生,就要尽量的遵照单一职责原则。此原则的核心就是解耦和加强内聚性。"

一个类有且只有一个能够改变的理由。

 

 

liskov替换原则(LSP)

  1. 子类必须可以替换它们的基类(IS-A)。

  2. 继承表达类型抽象。

 

接口隔离原则(ISP)

  1. 不能够强迫客户程序依赖他们不用的方法。

  2. 接口应该小而完备。

 

 

几个额外的建议:

组合复用原则(carp):

优先使用对象组合,而不是类继承

  1. 类继承一般为“白箱复用”,对象组合一般为“黑箱复用”。

  2. 继承在某种程度上破坏了封装性,之类父类耦合度高。

  3. 而对象组合则只要求被组合的对象具备良好定义的接口,耦合度低

 

封闭变化点

    使用封装来建立对象之间的分界层。让设计者能够在变化一侧进行修改,而不会影响另外一侧产生不良影响,从而实现松耦合。

 

针对接口编程

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

    1.不将变量类型声明为某个特定的具体类,而是声明为某个接口

    2.客户程序不须要获知对象的具体类型,只须要知道对象所具备的接口。

    3.减小系统中各部分的依赖关系,从而实现“高内聚,松耦合”的设计类型。

对设计模式按照目的分类能够分为如下三种:

1.建立型:与对象建立有关。

2.结构型:处理类或对象的组合。

3.行为型:模式对类或者对象怎么交互和分配职责进行描述。

按照其做用范围又可分为类模式对象模式 ,前者主要处理类和子类的关系,经过继承创建,具备静态,在编译时刻就稳定下来。后者处理对象之间的关系,这些关系多是运行时刻变化的,具备动态性。

具体模式能够参考书上的表格:

 

如何使用设计模式:

我想大概是要达到对症下药的层次吧,在此以前,咱们更应该关注原则。

相关文章
相关标签/搜索