简体   繁体   English

面向对象的设计?

[英]Object oriented design?

I'm trying to learn object oriented programming, but am having a hard time overcoming my structured programming background (mainly C, but many others over time). 我正在尝试学习面向对象的程序设计,但是很难克服我的结构化程序设计背景(主要是C,但是随着时间的推移会出现许多其他问题)。 I thought I'd write a simple check register program as an exercise. 我以为我会写一个简单的支票登记程序作为练习。 I put something together pretty quickly (python is a great language), with my data in some global variables and with a bunch of functions. 我很快将某些东西放在一起(python是一种很棒的语言),我的数据包含了一些全局变量和一些函数。 I can't figure out if this design can be improved by creating a number of classes to encapsulate some of the data and functions and, if so, how to change the design. 我无法弄清楚是否可以通过创建一些类来封装一些数据和功能,以及如何更改设计来改进此设计。

My data is basically a list of accounts ['checking', 'saving', 'Amex'], a list of categories ['food', 'shelter', 'transportation'] and lists of dicts that represent transactions [{'date':xyz, 'cat':xyz, 'amount':xyz, 'description':xzy]. 我的数据基本上是一个帐户列表['checking','saving','Amex'],一个类别列表['food','shelter','transportation']和代表交易的字典列表[{'date ':xyz,'cat':xyz,'amount':xyz,'description':xzy]。 Each account has an associated list of dicts. 每个帐户都有一个相关的字典列表。

I then have functions at the account level (create-acct(), display-all-accts(), etc.) and the transaction level (display-entries-in-account(), enter-a-transaction(), edit-a-transaction(), display-entries-between-dates(), etc.) 然后,我在帐户级别(create-acct(),display-all-accts()等)和交易级别(即display-entries-in-account(),enter-a-transaction(),edit)中具有函数-a-transaction(),display-entries-between-dates()等)

The user sees a list of accounts, then can choose an account and see the underlying transactions, with ability to add, delete, edit, etc. the accounts and transactions. 用户将看到一个帐户列表,然后可以选择一个帐户并查看基础交易,并具有添加,删除,编辑等功能。

I currently implement everything in one large class, so that I can use self.variable throughout, rather than explicit globals. 我目前在一个大类中实现所有内容,以便可以在整个过程中使用self.variable,而不是显式的全局变量。

In short, I'm trying to figure out if re-organizing this into some classes would be useful and, if so, how to design those classes. 简而言之,我试图弄清楚将其重新组织成某些类是否有用,如果有用,如何设计这些类。 I've read some oop books (most recently Object-Oriented Thought Process). 我读过一些糟糕的书(最近的面向对象的思想过程)。 I like to think my existing design is readable and does not repeat itself. 我想认为我现有的设计可读且不会重复。

Any suggestions would be appreciated. 任何建议,将不胜感激。

You don't have to throw out structured programming to do object-oriented programming. 您不必扔掉结构化的程序即可进行面向对象的程序设计。 The code is still structured, it just belongs to the objects rather than being separate from them. 该代码仍然是结构化的,仅属于对象而不是与它们分离。

In classical programming, code is the driving force that operates on data, leading to a dichotomy (and the possibility that code can operate on the wrong data). 在经典编程中,代码是对数据进行操作的驱动力,导致二分法(以及代码对错误数据进行操作的可能性)。

In OO, data and code are inextricably entwined - an object contains both data and the code to operate on that data (although technically the code (and sometimes some data) belongs to the class rather than an individual object). 在OO中,数据和代码密不可分-既包含数据又包含对数据进行操作的代码(尽管从技术上讲,代码(有时是某些数据)属于类而不是单个对象)。 Any client code that wants to use those objects should do so only by using the code within that object. 想要使用这些对象的任何客户端代码都应仅通过使用该对象内的代码来这样做。 This prevents the code/data mismatch problem. 这样可以防止代码/数据不匹配的问题。

For a bookkeeping system, I'd approach it as follows: 对于簿记系统,我将采用以下方法:

  1. Low-level objects are accounts and categories (actually, in accounting, there's no difference between these, this is a false separation only exacerbated by Quicken et al to separate balance sheet items from P&L - I'll refer to them as accounts only). 低级对象是科目和类别(实际上,在会计中,两者之间没有区别,这是一种错误的分离,只有Quicken等人将其从损益表中分离资产负债表项目时才加剧,我将它们仅称为科目)。 An account object consists of (for example) an account code, name and starting balance, although in the accounting systems I've worked on, starting balance is always zero - I've always used a "startup" transaction to set the balanaces initially. 帐户对象由(例如)帐户代码,名称和期初余额组成,尽管在我处理过的会计系统中,期初余额始终为零-我一直都使用“启动”交易来初始设置平衡。
  2. Transactions are a balanced object which consist of a group of accounts/categories with associated movements (changes in dollar value). 交易是一个平衡的对象,由一组具有相关移动(美元价值变化)的帐户/类别组成。 By balanced, I mean they must sum to zero (this is the crux of double entry accounting). 通过平衡,我的意思是它们必须总和为零(这是重复输入会计的关键)。 This means it's a date, description and an array or vector of elements, each containing an account code and value. 这意味着它是日期,描述以及元素的数组或向量,每个元素都包含一个帐户代码和值。
  3. The overall accounting "object" (the ledger) is then simply the list of all accounts and transactions. 这样,整个会计“对象”(分类帐)就是所有帐户和交易的清单。

Keep in mind that this is the "back-end" of the system (the data model). 请记住,这是系统(数据模型)的“后端”。 You will hopefully have separate classes for viewing the data (the view) which will allow you to easily change it, depending on user preferences. 希望您将有单独的类来查看数据(视图),这将使您可以轻松地根据用户的喜好更改数据。 For example, you may want the whole ledger, just the balance sheet or just the P&L. 例如,您可能需要整个分类帐,仅资产负债表或损益表。 Or you may want different date ranges. 或者您可能想要不同的日期范围。

One thing I'd stress to make a good accounting system. 我要强调的是要建立一个好的会计系统。 You do need to think like a bookkeeper. 确实需要像簿记员一样思考。 By that I mean lose the artificial difference between "accounts" and "categories" since it will make your system a lot cleaner (you need to be able to have transactions between two asset-class accounts (such as a bank transfer) and this won't work if every transaction needs a "category". The data model should reflect the data, not the view. 我的意思是失去“帐户”和“类别”之间的人为区别,因为这将使您的系统更加整洁(您需要能够在两个资产类帐户之间进行交易(例如银行转帐),并且这会赢得如果每个事务都需要一个“类别”,则该方法将不起作用。数据模型应反映数据,而不是视图。

The only difficulty there is remembering that asset-class accounts have the opposite sign from which you expect (negative values for your cash-at-bank mean you have money in the bank and your very high positive value loan for that company sports car is a debt , for example). 唯一的困难是要记住,资产类帐户的预期符号相反(银行现金的负值表示您在银行中有钱,而该公司跑车的高正值贷款是债务 )。 This will make the double-entry aspect work perfectly but you have to remember to reverse the signs of asset-class accounts (assets, liabilities and equity) when showing or printing the balance sheet. 这将使重复输入方面的工作完美无缺,但是在显示或打印资产负债表时,您必须记住要扭转资产类帐户的迹象(资产,负债和权益)。

Not a direct answer to your question but O'Reilly's Head First Object-Oriented Analysis and Design is an excellent place to start. 这不是您问题的直接答案,但是O'Reilly的Head First面向对象分析和设计是一个很好的起点。

Followed by Head First Design Patterns 其次是先头设计模式

"My data is basically a list of accounts" “我的数据基本上是帐户列表”

Account is a class. 帐户是一门课。

"dicts that represent transactions" “代表交易的命令”

Transaction appears to be a class. 交易似乎是一类。 You happen to have elected to represent this as a dict. 您恰好选择将其表示为dict。

That's your first pass at OO design. 这是您面向对象设计的第一步。 Focus on the Responsibilities and Collaborators. 专注于责任和合作者。

You have at least two classes of objects. 您至少有两类对象。

There are many 'mindsets' that you could adopt to help in the design process (some of which point towards OO and some that don't). 您可以采用许多“思想”来帮助设计过程(其中有些指向OO,有些则没有)。 I think it is often better to start with questions rather than answers (ie rather than say, 'how can I apply inheritance to this' you should ask how this system might expect to change over time). 我认为通常最好从问题开始,而不是从答案开始(即,与其说“我如何将继承应用于此”,不如问这个系统可能随着时间的变化而变化)。

Here's a few questions to answer that might point you towards design principles: 以下是一些可以回答的问题,这些问题可能会指向设计原则:

  • Are other's going to use this API? 其他人会使用这个API吗? Are they likely to break it? 他们有可能打破它吗? ( info hiding ) 信息隐藏
  • do I need to deploy this across many machines? 我需要在许多机器上部署它吗? ( state management, lifecycle management ) 状态管理,生命周期管理
  • do i need to interoperate with other systems, runtimes, languages? 我是否需要与其他系统,运行时,语言进行互操作? ( abstraction and standards ) 抽象和标准
  • what are my performance constraints? 我的表现受到哪些限制? ( state management, lifecycle management ) 状态管理,生命周期管理
  • what kind of security environment does this component live in? 该组件位于哪种安全环境中? ( abstraction, info hiding, interoperability ) 抽象,信息隐藏,互操作性
  • how would i construct my objects, assuming I used some? 假设我使用了一些对象,我将如何构造我的对象? ( configuration, inversion of control, object decoupling, hiding implementation details ) 配置,控制反转,对象解耦,隐藏实现细节

These aren't direct answers to your question, but they might put you in the right frame of mind to answer it yourself. 这些不是您问题的直接答案,但它们可能使您处于正确的思维方式来自己回答。 :) :)

Rather than using dicts to represent your transactions, a better container would be a namedtuple from the collections module. 与其使用字典来表示交易,不如使用更好的容器作为集合模块中的namedtuple。 A namedtuple is a subclass of tuple which allows you to reference it's items by name as well as index number. namedtuple是tuple的子类,它使您可以按名称和索引号引用其项。

Since you may possibly have thousands of transactions in your journal lists, it pays to keep these items as small and light-weight as possible so that processing, sorting, searching, etc. is as fast and responsive as possible. 由于您的日记帐列表中可能有成千上万笔交易,因此有必要将这些项目保持尽可能小巧轻便,以使处理,排序,搜索等操作尽可能快且响应迅速。 A dict is a fairly heavy-weight object compared to a namedtuple which takes up no more memory than an ordinary tuple. 与namedtuple相比,dict是一个相当重的对象,它比普通tuple占用的内存更多。 A namedtuple also has the added advantage of keeping it's items in order, unlike a 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

So you see that's almost 9 times saving in memory for an eight item transaction. 因此,您发现八项交易节省的内存几乎是9倍。 I'm using Python 3.1, so your milage may vary. 我使用的是Python 3.1,因此您的里程可能会有所不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM