存储库模式(续)- 类方法还是存储库方法?
给定一个结构,比如一个银行账户。
class Account
{
virtual int Id { get; set; }
virtual int Balance { get; set; }
}
我想跟踪已完成的交易,所以说一个简单的类...
class Transaction
{
virtual int Id { get; set; }
virtual Account Account { get; set; }
virtual DateTime Timestamp { get; set; }
virtual int Amount { get; set; }
}
让我们假设我想跟踪已完成的交易,这是更智能的方法吗?
interface IAccountRepository
{
void Deposit(int account, int amount)
}
或者...
class Account
{
void Deposit(int amount)
{
// this one is easier, but then I have to repeat
// myself because I need to store the Transaction
// in the database too.
}
}
存储库模式似乎是最具包容性的,因为它将具有工作/orm/会话单元的句柄(使用nHibernate) - 但使用类级方法似乎更简单,因为它更符合遵循“对此对象执行此操作”的标准面向对象原则。
我的问题是,如果我想记录事务,那么我必须确保它们也保存为数据库对象。采用第二条路线,使用类级别方法,我无法在 Account
类内部执行此操作,因此我最终不得不重复自己。
我的另一个选择是另一个抽象。
interface ITransactionRepository
{
void CreateTransaction(int account, int amount);
}
它工作得很好,它将 A 和 B 包装在一起,因为我会在 TransactionRepository
中找到帐户,然后执行其 Deposit
方法,但感觉这并不是一个明智的做法。我不知道为什么,我的直觉告诉我这不是最好的方法。
当然,这不仅仅适用于这一组类 - 这是一个设计原则。我想看看更多资深程序员在这种情况下会做什么,如果你有什么想法的话。
Given a structure for say, a bank account..
class Account
{
virtual int Id { get; set; }
virtual int Balance { get; set; }
}
And I want to track transactions done, so say a simple class...
class Transaction
{
virtual int Id { get; set; }
virtual Account Account { get; set; }
virtual DateTime Timestamp { get; set; }
virtual int Amount { get; set; }
}
Let's assume I want to keep track of transactions done, which is the more intelligent approach here?
interface IAccountRepository
{
void Deposit(int account, int amount)
}
or ...
class Account
{
void Deposit(int amount)
{
// this one is easier, but then I have to repeat
// myself because I need to store the Transaction
// in the database too.
}
}
The Repository pattern seems to be the most encompassing, since it will have a handle to the unit of work/orm/session (using nHibernate) - but using a class-level method seems more straightforward, since it's more in line with standard object oriented principle of 'Do this to this object'.
My question is that if I want to log the transactions, then I have to make sure they get saved as database objects too. Going the second route, with a class level method, I can't do this inside of the Account
class, so I would end up having to repeat myself.
My other option is another abstraction..
interface ITransactionRepository
{
void CreateTransaction(int account, int amount);
}
Which works fine, It kind of wraps A and B together because I would find the account in the TransactionRepository
and then perform its Deposit
method, but it doesn't really feel like this is a wise approach. I don't know why, my gut just tells me it isn't the best way to go.
This applies to more than just this one set of classes, of course - it's a principle of design. I wanted to see what more veteran programmers would do in this situation, if you have any thoughts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我建议使用 CRUD 的存储库模式(创建、读取、更新、删除)对账户的操作。
然后像您提到的那样将 Deposit 方法放入 Account 类中
然后您通过存储库访问帐户以更新帐户
交易可以以类似的方式完成,但我可能会存储帐户 ID,而不是交易中的帐户实例。
I would sugguest using the repository pattern for CRUD (Create, read, update, delete) operations on the Accounts.
Then put the Deposit method in the Account class like you mentioned
Then you access the account through the repository to update the account
Transations could be done in a similar way, but I would probably store the account id, rather than the Account instance in the Transcation.
你的问题是结构性 DB/OO 不匹配引起的问题的一个很好的例子。根据我的经验,人们倾向于支持您描述的第一个选项 - 绕过帐户业务对象并使用存储库将事务存储在数据库中。
我强烈建议不要让你的数据库结构影响业务层设计。业务对象用于实现业务行为。当您直接访问存储库以执行从业务角度来看属于 Account 类的操作时,您的业务规则最终将位于一个奇怪的位置 - Account 类之外的某个位置。
为了回答您的问题,我在这些情况下始终采取的方法如下:
在业务逻辑中遵守面向对象的原则。根据实际流程构建您的类和交互,以便业务规则最终会出现在您期望的位置。
为数据库提供面向存储的视图。我的意思是,您的存储库不需要模仿业务对象的结构。例如,实现一个为帐户和交易执行 CRUD 的存储库。
Your question is a nice example of problems that arise from the structural DB / OO mismatch. In my experience, people tend to favor the first option you described - bypass the Account business object and store the Transaction in the DB by using the repository.
I strongly recommend not to let your DB structure influence the business layer design. Business objects are there to implement business behavior. When you access the repository directly for an operation that belongs to the Account class from a business point-of-view, your business rules will end up at a strange location - somewhere outside the Account class.
To answer your question, the approach that I always take in these situations is as follows:
Adhere to OO principles in your business logic. Structure your classes and interactions according to real-world processes, so business rules end up where you'd expect them.
Provide a storage-oriented view to the DB. What I mean with this is that your repository needs not mimic the structure of your business objects. For example, implement an repository that does CRUD for accounts and the transactions.