面向对象设计?
我正在学习面向对象编程,但很难摆脱我之前的结构化编程背景(主要是C语言,还有很多其他语言)。我想写一个简单的记账程序作为练习。我很快就写好了(Python是一门很棒的语言),我的数据放在一些全局变量里,还有很多函数。我现在搞不清楚,是否可以通过创建一些类来改进这个设计,以便更好地封装一些数据和函数,如果可以的话,应该怎么改变设计。
我的数据基本上包括一个账户列表 ['checking', 'saving', 'Amex'],一个类别列表 ['food', 'shelter', 'transportation'],以及表示交易的字典列表 [{'date':xyz, 'cat':xyz, 'amount':xyz, 'description':xyz}]。每个账户都有一个相关的字典列表。
然后我在账户层面有一些函数(比如 create-acct()、display-all-accts() 等),在交易层面也有函数(比如 display-entries-in-account()、enter-a-transaction()、edit-a-transaction()、display-entries-between-dates() 等)。
用户可以看到账户列表,然后选择一个账户,查看底下的交易记录,还可以添加、删除、编辑账户和交易。
目前我把所有东西都放在一个大类里,这样我可以在整个程序中使用 self.variable,而不需要使用全局变量。
总之,我想弄清楚把这些内容重新组织成几个类是否有用,如果有的话,应该怎么设计这些类。我看过一些面向对象编程的书(最近读的是《面向对象的思维方式》)。我觉得我现在的设计是可读的,并且没有重复的部分。
任何建议都非常感谢。
5 个回答
“我的数据基本上就是一个账户的列表。”
账户是一个类。
“字典用来表示交易。”
交易看起来也是一个类。你选择用字典来表示它。
这就是你第一次尝试面向对象设计。要关注每个对象的职责和它们之间的合作关系。
你至少有两种类型的对象。
这不是直接回答你问题的内容,但O'Reilly出版的《Head First 面向对象分析与设计》是一个很好的入门书籍。
接下来可以看看《Head First 设计模式》。
你不需要放弃结构化编程就能做面向对象编程。代码依然是有结构的,只不过它属于对象,而不是和对象分开。
在传统编程中,代码是操作数据的主要力量,这就导致了代码和数据之间的分离(并且可能会出现代码操作了错误的数据)。
在面向对象编程中,数据和代码是紧密结合在一起的——一个对象同时包含数据和操作这些数据的代码(虽然从技术上讲,代码(有时还有一些数据)属于类,而不是某个具体的对象)。任何想要使用这些对象的代码都应该通过对象内部的代码来进行。这可以避免代码和数据不匹配的问题。
对于一个记账系统,我会这样设计:
- 低级别的对象是账户和类别(实际上,在会计中这两者没有区别,这种分离是错误的,只有像Quicken这样的软件才会把资产负债表项目和损益表分开——我只称它们为账户)。一个账户对象包含(例如)账户代码、名称和初始余额,虽然在我参与的会计系统中,初始余额通常都是零——我总是用一个“启动”交易来设置初始余额。
- 交易是一个平衡的对象,由一组账户/类别和相关的变动(金额变化)组成。这里的“平衡”是指它们的总和必须为零(这就是复式记账的核心)。这意味着交易包含日期、描述和一个元素数组或向量,每个元素都包含一个账户代码和金额。
- 整体的会计“对象”(账本)就是所有账户和交易的列表。
请记住,这只是系统的“后端”(数据模型)。你希望有单独的类来查看数据(视图),这样可以根据用户的偏好轻松修改数据。例如,你可能想查看整个账本、仅查看资产负债表或仅查看损益表,或者想要不同的日期范围。
我想强调的是,想要做好一个会计系统,你确实需要像一个记账员那样思考。我的意思是要消除“账户”和“类别”之间的人工区别,因为这样会让你的系统更简洁(你需要能够在两个资产类账户之间进行交易(比如银行转账),而如果每个交易都需要一个“类别”,这就行不通了)。数据模型应该反映数据,而不是视图。
唯一的难点是要记住资产类账户的符号和你预期的相反(例如,银行账户的负值意味着你在银行里有钱,而你那辆公司跑车的高额正值贷款则是一个“债务”)。这会让复式记账的部分运作得非常完美,但你必须记得在显示或打印资产负债表时要反转资产类账户(资产、负债和权益)的符号。