美文网首页
盲人摸象之于软件编程

盲人摸象之于软件编程

作者: going_hlf | 来源:发表于2016-11-07 21:45 被阅读61次
盲人摸象

盲人摸象这个成语故事,大家一定不陌生。它比喻对事物只凭片面的了解或局部的经验,就乱加猜测,想做出全面的判断。用来讽刺人的目光短浅,片面。多少年来,这个成语一直作为一个贬义词沿用至今。

而在最近一些年,很多软件大师包括一些国外的大师都借用盲人摸象这个典故作为软件编程的一个隐喻,形象地说明了很多软件开发的原则和理念。在软件编程的世界里,盲人摸象的故事成了一个褒义词。

可能大家已经能够想到了,盲人摸象跟软件设计中的封装、隐藏的概念是如此的契合。封装和隐藏的概念在面向对象(C++、JAVA等)的世界里是核心内容,即便是在面向过程的C语言中,如今的编程理念也处处体现了封装的味道。之所以如此强调封装和隐藏,是因为软件设计中解耦的需要。我们常常挂在嘴边的高内聚低耦合,就是要我们做到很好的封装和隐藏。

下面举几个封装和隐藏的例子,一起体会一下:

C语言程序中,数据结构+算法的一段程序可能是这个样子。
//data.h

void processDataA();
void processDataB();

//data.c

DATA gDataA = 0;
DATA gDataB = 0;

void processDataA()
{
    // call gDataA
}

void processDataB()
{
    // call gDataB
}

下面对gDataAgDataB的使用可能是你不期望的,但是你无法阻拦,原因是你把数据暴露给了所有人。
//other.c

extern DATA gDataA;
extern DATA gDataB;

void otherFunc()
{
    // call gDataA
    // call gDataB
}

为了阻止这种随意访问,我们可以用类对数据和方法做个封装,实现数据的私有化,像下面这个样子。
//data.h

class DataAProcessor
{
public:
    void process();

private:
    DATA dataA;
};

class DataBProcessor
{
public:
    void process();

private:
    DATA dataB;
};

//data.cpp

void DataAProcessor::process()
{
    //call dataA
}

void DataBProcessor::process()
{
    //call dataB
}

这样,再企图去滥用数据dataAdataB的函数,将会被拒之门外。

#include "data.h"

void otherFunc()
{
    // call DataAProcessor::dataA, error
    // call DataBProcessor::dataB, error
}

其实类除了限制了数据的访问权限,更重要的是,它把数据和操作数据的方法作为一个完整的概念聚合了在了一起。

在高内聚、低耦合的概念如此深入人心的今天,封装和隐藏技术已经不仅仅体现在类上,它无处不在。在编程的世界里,人们应该是自私的,在没有足够的理由暴露某个数据之前,它应该是被隐藏的。

让我们继续探讨信息隐藏。
假设我们需要新增DataAProcessorprint方法。
//data.h

class DataAProcessor
{
public:
    void process();
    void print();

private:
    DATA dataA;
};

class DataBProcessor
{
public:
    void process();

private:
    DATA dataB;
};

这个操作会导致所有包含了data.h的文件都要重新编译。而对于下面的dataBUser.cpp,实在是编译的很冤枉。因为它并没有使用DataAProcessor中的任何数据和成员,由于DataAProcessor中新增了一个方法,却导致了自己的重新编译。
//dataBUser.cpp

#include "data.h"

void handleDataB()
{
    DataBProcessor::process();
}

这种情况在我们的项目工程中十分常见,不合理的头文件依赖,牵一发而动全身,导致了编译时间加长,令人难以忍受。

仍然是使用隔离和隐藏技术,我们把文件拆开,从这个意义上讲,文件也是一种封装技术。
//dataA.h

class DataAProcessor
{
public:
    void process();

private:
    DATA dataA;
};

//dataB.h

class DataBProcessor
{
public:
    void process();

private:
    DATA dataB;
};

//dataA.cpp

void DataAProcessor::process()
{
    //call dataA
}

//dataB.cpp

void DataBProcessor::process()
{
    //call dataB
}

这样分开后,变得清爽了很多,各自互不影响。一个文件对应一个类,同时对应一个概念。

再进一步,假设DataBProcessor需要新增一个方法,该方法仅仅类内部使用。但凡有隐藏意识的人,都很容易想到使用private。可能像这样:
//dataB.h

class DataBProcessor
{
public:
    void process();

private:
    bool isDataAvailable();

private:
    DATA dataB;
};

//dataB.cpp

void DataBProcessor::isDataAvailable()
{
    return dataB != 0;
}

void DataBProcessor::process()
{
    if(isDataAvailable())
    {
        //call dataB
    }
}

能够想到把方法isDataAvailable private起来,已经对信息隐藏有了很好的意识。但是,在dataB.h中让用户看到这个方法,仍然显得有些碍眼,从某种意义上讲,我们把自己的实现细节暴露给了用户。而原本我们只应该暴露用户接口。

通常,不需要给用户使用的方法,不要放在头文件中(这个对于C语言同样适用),应该把它完全隐藏在实现文件中。为了防止跟别的文件中的函数重名,可以使用匿名命名空间namespace,像这样:

//dataB.cpp

namespace
{
    void isDataAvailable(DATA data)
    {
        return data != 0;
    }
}

void DataBProcessor::process()
{
    if(isDataAvailable(dataB))
    {
        //call dataB
    }
}

我们称这种文件规划和信息隐藏技术为物理设计。物理设计已经成为一个衡量软件设计好坏的重要指标。

上面说了一大堆面向对象的信息隐藏技术,有人可能要说,我们现在用的是C语言,怎么用的你方法做信息隐藏?其实上面已经说到了,信息隐藏是一种编程理念,并非针对某种编程语言的特有的技术。

对于C语言,用static修饰函数,不把函数声明暴露在头文件中(前提是这个函数没有外部用户使用),就是一项很好的封装和信息隐藏技术,其实static等同于C++的namespace

但是大多数传统的C程序员,一个固定的思维是,在.c里面实现的函数,一定要在.h中声明。甚至有人危言耸听说不这样做,编译不过。

对于C语言,把一堆相互关联的数据和方法归类集中在同一个文件中,就是一种概念的抽象和封装。这就是为什么有面向对象思想的程序员,写出的C程序,也处处透出面向对象的味道。

这篇文章就到这里,欢迎大家一起探讨。

相关文章

  • 盲人摸象之于软件编程

    盲人摸象这个成语故事,大家一定不陌生。它比喻对事物只凭片面的了解或局部的经验,就乱加猜测,想做出全面的判断。用来讽...

  • 解决项目管理中的“盲人摸象”现象

    盲人摸象的故事源之于《大般涅盘经》,是一个大家比较熟悉的典故。每当说起盲人摸象,人们都会为故事中的情节所逗乐。一个...

  • 我们用的软件是编程软件编的,那编程软件是用什么编的?

    我们手机的APP,电脑的APP。都是软件,我们用的软件都是用编程软件编的。 实际上,编程软件也是软件,所以编程软件...

  • 《Google 软件工程》 读书笔记1

    软件工程VS编程 软件工程就是随时间不断集成的编程。 思考:编程是需要考虑时间维度的,软件的生命长度决定了编程时需...

  • 仰望星空,脚踏实地

    模式是一种特定结构,《建筑模式语言》之于建筑设计,《设计模式》之于软件开发,《聪明的投资者》之于价值投资,《人生模...

  • Think in Java

    一切皆对象 引用 每种编程语言都有操纵内存中元素的方式。例如C/C++之于指针、Java之于引用把对象看作电视机(...

  • scratch

    Scratch这款软件最便捷的地方在于图形化编程过程。图形化编程scratch是一种为儿童开发的编程软件,由MIT...

  • Swift学习软件推荐

    Swift学习软件推荐 这里给大家推荐一款Swift编程语言的学习软件——编程雨燕。我们先来看一下软件的内容: 整...

  • [译] Lisp之根源(一)

    1960年,约翰·麦卡锡发表了一篇意义非凡的论文。其价值之于编程,犹如欧基里德的《几何原本》之于几何学。论文展示了...

  • 编程第一课

    什么是IT?什么是编程?软件是什么?软件怎么分类?都有哪些常用编程语言?它们都是做什么的?欢迎来到编程第一课! B...

网友评论

      本文标题:盲人摸象之于软件编程

      本文链接:https://www.haomeiwen.com/subject/rsaouttx.html