面向对象的设计?

时间:2009-10-22 00:25:17

标签: python oop

我正在尝试学习面向对象的编程,但我很难克服我的结构化编程背景(主要是C,但随着时间的推移,很多其他人)。我以为我会写一个简单的支票登记程序作为练习。我把一些东西很快地放在了一起(python是一种很棒的语言),我的数据包含在一些全局变量和一堆函数中。我无法弄清楚是否可以通过创建一些类来封装一些数据和函数来改进这种设计,如果是这样,如何更改设计。

我的数据基本上是一个帐户列表['check','Saving','Amex'],一个类别列表['food','shelter','transportation']和代表交易的dicts列表[ {'date':xyz,'cat':xyz,'amount':xyz,'description':xzy]。每个帐户都有一个相关的词典列表。

然后我在帐户级别(create-acct(),display-all-accts()等)和事务级别(display-entries-in-account(),enter-a-transaction( ),edit-a-transaction(),display-entries-between-dates()等。)

用户会看到一个帐户列表,然后可以选择一个帐户并查看基础交易,并能够添加,删除,编辑等帐户和交易。

我目前在一个大类中实现所有内容,因此我可以使用self.variable,而不是显式的全局变量。

简而言之,我正在试图弄清楚是否将其重新组织到某些类中是有用的,如果是这样,那么如何设计这些类。我读过一些oop书籍(最近的面向对象思想过程)。我认为我现有的设计是可读的,不会重演。

任何建议都将不胜感激。

5 个答案:

答案 0 :(得分:7)

您不必抛弃结构化编程来进行面向对象的编程。代码仍然是结构化的,它只是属于对象而不是与它们分开。

在经典编程中,代码是对数据进行操作的驱动力,导致二分法(代码可以在错误的数据上运行)。

在OO中,数据和代码是密不可分的 - 一个对象包含数据和操作该数据的代码(尽管从技术上讲,代码(有时是某些数据)属于类而不是单个对象)。任何想要使用这些对象的客户端代码都应该只使用该对象中的代码。这可以防止代码/数据不匹配问题。

对于簿记系统,我会按如下方式处理:

  1. 低级别的对象是账户和类别(实际上,在会计中,这些之间没有区别,这是一种错误的分离,只会加剧Quicken等将资产负债表项目与P& L分开 - 我会参考它们仅作为帐户)。一个帐户对象包括(例如)帐户代码,名称和起始余额,尽管在我所使用的会计系统中,起始余额始终为零 - 我总是使用“启动”事务来初始设置balanaces
  2. 交易是一个平衡的对象,由一组具有相关变动的账户/类别组成(美元价值的变化)。平衡,我的意思是他们必须总和为零(这是双重会计核算的关键)。这意味着它是一个日期,描述和元素的数组或向量,每个元素都包含一个帐户代码和值。
  3. 整个会计“对象”(分类帐)只是所有帐户和交易的列表。
  4. 请记住,这是系统的“后端”(数据模型)。您希望有单独的类来查看数据(视图),这将允许您根据用户首选项轻松更改它。例如,您可能需要整个分类帐,只需要资产负债表或只需要P& L.或者您可能需要不同的日期范围。

    我强调要做一个好的会计系统。你需要像簿记员一样思考。我的意思是失去“帐户”和“类别”之间的人为差异,因为它会使您的系统更清洁(您需要能够在两个资产类帐户之间进行交易(例如银行转帐)如果每个事务都需要一个“类别”,那就无效了。数据模型应该反映数据,而不是视图。

    唯一的困难是记住资产级账户与您的预期相反(您的银行现金的负值意味着您在银行有钱,而您的非常高正面该公司跑车的价值贷款是债务,例如)。这将使双重进入方面完美运作,但您必须记住在显示或打印资产负债表时扭转资产类别账户(资产,负债和权益)的迹象。

答案 1 :(得分:5)

不是你问题的直接答案,但奥莱利的Head First Object-Oriented Analysis and Design是一个很好的起点。

其次是Head First Design Patterns

答案 2 :(得分:3)

“我的数据基本上是一个帐户列表”

帐户是一个类。

“表示交易的词汇”

交易似乎是一个类。你碰巧选择将其表示为一个字典。

这是你在OO设计上的第一次传球。专注于责任和合作者。

您至少有两类对象。

答案 3 :(得分:1)

您可以采用许多'思维模式'来帮助设计过程(其中一些指向OO而一些不指向OO)。我认为从问题而不是答案开始往往更好(即,而不是说'我怎样才能将继承应用于此',你应该问这个系统可能会随着时间的推移而变化)。

这里有几个问题需要回答,可能会指向设计原则:

  • 其他人会使用这个API吗?他们有可能打破它吗? (信息隐藏
  • 我是否需要在多台机器上部署它? (州管理,生命周期管理
  • 我是否需要与其他系统,运行时,语言进行互操作? (抽象和标准
  • 我的表现限制是什么? (州管理,生命周期管理
  • 此组件所处的安全环境是什么? (抽象,信息隐藏,互操作性
  • 假设我使用了一些,我将如何构建我的对象? (配置,控制反转,对象解耦,隐藏实现细节

这些不是您问题的直接答案,但它们可能会让您处于正确的心态,自己回答它。 :)

答案 4 :(得分:-1)

不是使用dicts来表示您的事务,更好的容器将是来自collections模块的namedtuple。 namedtuple是元组的子类,它允许您按名称和索引号引用它的项目。

由于您的日记列表中可能有数千个交易,因此尽可能保持这些项目的小巧轻便,以便处理,排序,搜索等尽可能快速且响应迅速。与命名元组相比,dict是一个相当重量级的对象,它不占用比普通元组更多的内存。与dict不同,namedtuple还具有保持其项目有序的附加优势。

>>> import sys
>>> from collections import namedtuple
>>> sys.getsizeof((1,2,3,4,5,6,7,8))
60
>>> ntc = namedtuple('ntc', 'one two three four five six seven eight')
>>> xnt = ntc(1,2,3,4,5,6,7,8)
>>> sys.getsizeof(xnt)
60
>>> xdic = dict(one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8)
>>> sys.getsizeof(xdic)
524

所以你看到,对于八项交易,内存几乎节省了9倍。 我正在使用Python 3.1,所以你的milage可能会有所不同。