谈谈面向对象

一、为什么要说这个话题?

我们搞软件的,对于“面向对象”这个词,都听到过无数遍。这是一个非常非常非常老旧的话题。想说一下这个话题,主要是受到几件事情的触动:

  1. 在参加面试时,问到对“面向对象”概念的理解,我们的面试官所期待的标准答案往往是,说出封装、继承、多态这三个特征,以及它们的含义。特别是多态的含义;
  2. 在一次架构师培训时,讲师谈到自己对“面向对象”的体会,说体会最深的是封装这一个特性,封装就是好呀!
  3. 最重要的是,我们现在实现的系统,虽然用的语言是C#,但几乎静态方法一路到底,或者相当于静态方法一路到底。

这都让我认为,虽然“面向对象”是一个非常非常非常老旧的话题,但对它的理解还很难说得上到位。有谈谈的必要。

二、“面向对象”是什么?

随着面向对象在程序设计领域大行其道,它也逐步入侵到软件开发的其它领域:面向对象分析、面向对象设计、面向对象数据库,我还见过面向提对象测试的。在这些领域中,除了在数据库领域败给关系技术外,面向对象所向披靡。

那么,面向对象到底是什么,是需求分析技术,软件设计技术,还是程序编码技术?都是。但这些技术背后,应该有一种共通的东西。这种共通的东西,应用到不同的领域,就表现为不同的技术。所谓“天地有正气,杂然赋流形。下则为河岳,上则为日星。”那么,这种共通的东西是什么?

我认为是一种方法论,面向对象归根结蒂是一种方法论。下面是对于面向对象的谭氏定义:

面向对象是描述和构建系统的方法论,该方法论认为,一个系统由相互作用的对象组成,对象的状态决定了系统的状态,对象的行为决定了系统的行为。对象是通过抽象得到的,一个对象是对相关状态和行为的封装,继承是对象之间一种重要的关系,对象的行为往往是多态的。

这个定义兼顾了分析、设计和开发。其中分析是在描述一个系统,设计和开发则是在构建系统。其核心在于,指出一个系统是由相互作用的对象组成的。我们在开发一个系统时,应该满脑子想的都是对象,将注意力集中到对象上:如何提炼对象,如何定义对象的状态和行为,如何建立对象之间的关系,如何创建和销毁对象,等等。

说句题外话。在名字上,“面向对象”翻译得有点不妥,不能很好地反映原文“Object Oriented”的含义。我曾听到两个台湾同行聊天,取笑我们的翻译:“你知道什么是‘面向对象’吗?原来就是‘物件导向’呀,哈哈哈!”我觉得他们确实有理由取笑,“物件导向”确实更为贴切,更能反映出原意。“面向对象”用做微博上的一个程序员征婚活动的名字,倒是更合适一些。

三、“伪面向对象”的表现

面向对象是一种方法论,不采用这种方法论指导行动,即便利用了面向对象的工具,如利用C#、Java这样的面向对象语言进行开发,也不一定是真正的面向对象,我们不妨称之为“伪面向对象”。

“伪面向对象”是面向过程的思维方式导致的。我们知道,面向对象是为了克服面向过程的缺点发展起来的,如果仍然使用面向过程的思维,自然就做不好面向对象。

那么具体表现是什么?最为突出的有两点。

提出第一点之前先说一段经历。老谭曾经管理过一个开发小组,用的开发语言是C++。但是我注意到小组中有一位,仍然在用C进行开发,没有利用C++中面向对象的任何特征。这和团队的风格不一致,我要求她(真的是她啊)利用C++重构。刚过了半天,这位神人就说重构好了,已经改为C++了。我一看,确实在用C++,因为定义了类,所有方法都放到了类中。但和没用C++几乎没有区别,仅仅是在类上加了一个static关键字而已。

所以,“伪面向对象”的第一点表现是,虽然定义了类,但逻辑是,或者主要是由静态方法实现的。

在这种情况下,基本上没有有效提炼对象,自然就谈不上真正的面向对象。

使用静态方法,不一定表现为在方法前面加上了static关键字。有些没有static关键字的方法,其实质上仍然是静态方法。

我们目前的项目就是合适的例子。该项目的技术架构,分为展现层、服务接口层、业务逻辑层、数据访问层。从服务层开始,均通过接口向上层提供服务,而每层服务的实现,有不少是在一个方法中通过调用下层的接口完成。

例如,服务接口层提供获取管网的服务,定义了接口:

public interface ICommonService
{
    ......
    EnergyNet GetEnergeNet(long netId);
    ......
}

并予以实现:

public class CommonService : ICommonService
{
    private ICommonServiceImp imp;

    ......
    public EnergyNet GetEnergeNet(long netId)
    {
        return imp.GetEnergyNet(netId);
    }
    ......
}

自然,业务逻辑层也提供了接口,并予以实现:

public interface ICommonServiceImp
{
    ......
    EnergyNet GetEnergyNet(long netId);
    ......
}

public class CommonServiceImp : ICommonServiceImp
{
    private ICommonDao commonDao;
    ......
    public EnergyNet GetEnergyNet(long netId)
    {
        return commonDao.GetEnergyNet(netId);
    }
    ......
}
同样的故事也发生在数据访问层上。

这样的实现有两个特点:

  1. 所定义的类仅用于实现接口,如类CommonService仅用于实现接口ICommonService;
  2. 类方法中没有创建其它对象。

对于这种实现,如果不是因为接口实现的关系,这些类和静态类是相当的,自然其中的方法也相当于静态方法。

“伪面向对象”的第二点表现是,长方法。一般我们将一个方法控制在20行内。富含业务逻辑的方法如果超过了50行,往往意味着程序员正在用过程化的思路处理问题,而没有抽象出必要的对象。在真正面向对象的方法中,会将复杂的业务逻辑分解到合适的对象中,原来的长方法也就分解为不同对象的多个短方法。

四、未完待续

这里我们从总体上描述了面向对象这一概念。老谭计划对面向对象的特征,即抽象、封装、继承、多态,一一进行剖析。但愿有精力和时间。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Python 面向对象编程中,容器类是指可以包含其他对象的类,例如列表、元组、字典等。Python 中的容器类通常都实现了一些特殊的方法,使得它们可以像原生的容器一样使用。 下面是一个简单的例子,演示了如何实现一个自定义的容器类: ```python class MyList: def __init__(self, *args): self.data = list(args) def __len__(self): return len(self.data) def __getitem__(self, index): return self.data[index] def __setitem__(self, index, value): self.data[index] = value def __delitem__(self, index): del self.data[index] def __iter__(self): return iter(self.data) def __contains__(self, value): return value in self.data ``` 在上面的例子中,我们定义了一个名为 `MyList` 的类,它实现了容器类的一些常用方法,包括 `__init__`、`__len__`、`__getitem__`、`__setitem__`、`__delitem__`、`__iter__` 和 `__contains__`。 我们通过 `__init__` 方法初始化了一个列表,然后通过 `__len__` 方法返回列表的长度,通过 `__getitem__` 方法实现了按下标访问元素的功能,通过 `__setitem__` 和 `__delitem__` 方法实现了设置和删除元素的功能,通过 `__iter__` 方法实现了迭代列表的功能,通过 `__contains__` 方法实现了判断元素是否存在的功能。 现在我们可以使用 `MyList` 类来创建一个列表对象,并像使用原生列表一样使用它: ```python mylist = MyList(1, 2, 3) print(len(mylist)) # 3 print(mylist[0]) # 1 mylist[0] = 0 print(mylist[0]) # 0 del mylist[0] print(len(mylist)) # 2 for item in mylist: print(item) # 2, 3 print(2 in mylist) # True print(0 in mylist) # False ``` 总之,容器类是 Python 面向对象编程中非常重要的一个概念,可以帮助我们更加灵活地处理数据,同时也为我们提供了许多常用的数据结构和算法实现。在编写自己的容器类时,我们可以根据需要实现容器类所需的特殊方法,从而实现自定义的容器类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值