Hacker News new | past | comments | ask | show | jobs | submit login

Without knowing any more about the system I'd suggest: contract.sign(property, buyer, seller, agent)

It seems that properties, buyers, sellers and agents could exist without 'knowing' about contracts, but a contract at some point needs to reference the other entities. Also, it seems odd that the contract can exist without knowing the details of buyer, seller, etc. I'd prefer: new Contract(property, buyer, seller, agent) and if possible make it immutable.




I would tend towards this solution as well, but does it meet the "looks natural" criteria? Contracts that sign themselves?

I think many classes we invent are nothing more than processes in disguise and we could just as well model them as functions.

A simpler example. Should the BankAccount class have a transferTo(BankAccount other) method to transfer money into another account? What if there are different account types and the exact process depends on the types of both accounts?

Of course it's possible to do it that way, but is it really the cleanest way to imagine this? I don't think so.


A simpler example. Should the BankAccount class have a transferTo(BankAccount other) method to transfer money into another account?

A BankAccount is a data object, so no processing in there. You could have a Banker object (or a MoneyExchanger object, which is "less real world" solution) which would be the actor object responsible for this task. So the natural message is myBanker.transferMoney(sourceBankAccount, targetBankAccount, amount).

What if there are different account types and the exact process depends on the types of both accounts?

You would need to handle of the possible cases into your actor object - which is why it is interesting here to have an actor object specialized in just that. There are several techniques you could apply to dispatch the call to the appropriate implementation of transferMoney().

I think many classes we invent are nothing more than processes in disguise and we could just as well model them as functions.

Well, yes, classes do things - at least actor objects do things. Btw actor objects generally have no state, so you can see them as "super functions", with many advantages over basic functions (inheritance, polymorphism etc).


OO purists actually frown upon the kind of stateless Manager objects you suggest. But I can imagine a scenario in which a money transfer would be something very complex that merits its own process class.

I just don't think it makes sense to mandate that kind of heavy weight function class for every operation or be forced to subordinate an operation to an arbitrary class. For instance, formatting a date in Java works like this:

  Date date = ...;
  DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
  String s = df.format(date);
So the date format formats the date. Why is that? Why is date subordinated to date format here? It could just as well be the other way around. There may be some implementation related reason for that but conceptually it makes no sense at all, it's impossible to guess and hard to remember.

  s = format(date, date_format) 
makes a lot more sense to me.


OO purists actually frown upon the kind of stateless Manager objects you suggest.

Yes, but pure OOP has been proven impractical many times over the last 20 years. What we are looking for here are practical rules that will help us organize our code in an OOP framework.

So the date format formats the date. Why is that? Why is date subordinated to date format here?

Actually the name "DateFormat" is unfortunate. It should have been "DateFormatter", because it is clearly an actor object - while a date is a data object. Suppose you have a fire in your house, you want help to extinguish it. So you call a fireman, and you basically say to him "here's a fire : do your job". In the present case you have a date, and you want to format it. So you "call" a DateFormat(ter) and you say "here is a date : do your job". That's exactly the same, natural principle of delegation. If you need something to be done, call an expert to do it for you.

Of course it gets quickly tedious having to explicitly call the actor objects for everything. So it might be useful to add "convenience methods" to the data objects, which would simply call the appropriate default actor and pass themselves as arguments to the work operation. So here you would then be able to call date.format(DateFormat.LONG), which means any date would basically become able to format itself. It has good and bad sides, and there is no clear answer (that I know of) to determine in which cases it's okay to do that or not.

s = format(date, date_format) makes a lot more sense to me

That's because you see formatting as an action, and you're thinking action => function. In an OO environment you should rather be seeing formatting as a responsibility, and thinking responsibility => class.


That's because you see formatting as an action, and you're thinking action => function. In an OO environment you should rather be seeing formatting as a responsibility, and thinking responsibility => class.

I understand what you're saying and I understand OO design very well because I used it for decades. I just don't agree. The question we're asking here, I think, is not "how should you behave in an OO environment?", the question is "is OO a good software design principle".

My answer to that is no, and your insistance on dividing classes into data and actor classes tells me that you're well on your way to joining my opinion soon ;-)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: