Hi…
OO can do that, but so does a simple function. Your problem is not yet complicated enough that you need the full power of OO. Funnily, because your problem is not hard enough, you have lot’s of solutions. Are you hopping from solution to solution, all of which could work, but you don’t know which is best?
Lots! I’ll throw in some scenarios and you can see how OO solves each.
- You just want to keep the date formatting code in one place and make it very obvious that’s where it is.
OO is a good tool for modularisation as well as for adding flex points…
class DocumentMetadata {
private $date;
function __construct($timestamp, ...) {
$this->date = new DateFormatter($timestamp);
...
}
function date() {
return $this->date->render();
}
}
class DateFormatter {
private $timestamp;
function __construct($timestamp) {
$this->timestamp = $timestamp;
}
function render() {
return ... // Mechanics of creating the string here.
}
}
Users of the DocumentMetadata never even know that it is using DateFormatter internally. It’s for your benefit only so that you can group date stuff out of DocumentMetadata to keep your head clear.
No OO Fu points yet, but less stress when you return to the code.
- You want to have multiple date formatting rules available, and the formatting is chosen at the time the DocumentMetadata class is constructed…
class DocumentMetadata {
private $date;
function __construct($date, ...) {
$this->date = $date;
...
}
function date() {
return $this->date->render();
}
}
You create the DocumentMetadata instance like so…
new DocumentMetadata(new DateFormatter($time), ...)
Now you could swap DateFormatter for UkDateFormatter or for UsDateFormatter and the document would work just fine.
We’ve added a flex point, namely the ability to choose the date format at construction time. We’ve made creating the DocumentMetadata a little more involved.
You get a grudging OO Fu point for mechanical skill, but there is something a little ugly in doing formatting in the DocumentMetadata class. It’s kind of doing two jobs.
- You want to add other methods to the DateFormatter, but you don’t want to keep messing With DocumentMetadata…
class DocumentMetadata {
private $date;
function __construct($date, ...) {
$this->date = $date;
...
}
function date() {
return $this->date;
}
}
class DateFormatter {
private $timestamp;
function __construct($timestamp) {
$this->timestamp = $timestamp;
}
function render() {
return ... // Mechanics here.
}
function renderAsWords() {
return ... // Mechanics here.
}
}
Dead simple. You set it up with a formatter and clients of the class get the whole object back to do with as they please. DocumentMetadata now knows nothing about formatting anything. The problem is that DocumentMetadata is a bit vacuous. You could have just used a hash or StdObject. If DocumentMetadata does something, like date calculations, it will have to know about the innards of $date anyway. It now knows nothing about DateFormatter
2 OO Fu points anyway, as this could be simplest solution in practice. There more refined solutions to this general problem, but my post would get too long.
- DocumentMetadata works with dates and fiddles with them internally, but you don’t want display code mixed in to it. You also want to choose formatting later in the code…
class DocumentMetadata {
private $date;
function __construct($date, ...) {
$this->date = $date;
...
}
function writeOfficialPublicationDate($formatter) {
$formatter->take($this->alwaysNoon($this->date));
}
function alwaysNoon($date) {
... // Our document handling works in mysterious ways
}
}
class DateFormatter {
function take($date) {
return ... // Mechanics here.
}
}
Now DataFormatter can do more than pass a string around. It can draw a whole display if needed. In fact it should. This trick solves the problem of passing data from class to class until it finds the target. Just take the mountain to Mohammid and save all those getters and setters.
This is not just super flexible, the formatting and the date calculations are completely independent, it’s also going to produce much less buggy code.
When we returned our DateFormatter object in example 3, suppose the DateFormatter had a method called setDate()? That means clients of DocumentMetadata could mess with it’s internals. That’s an invitation to buggy code. If you find all the dates are wrong, who was to blame. That DateFormatter could have been passed around quite a way. Even to a separate process if it was persisted to the database and back.
By handing clients the whole of DateFormatter we gave too much authority away. This breaks the “Principle of Least Authority” (POLA), usually more loosely termed encapsulation. Solution 4 does not do this.
DocumentMetadata is free to pass the DocumentFormatter by value in example 3, but it would have to know a bit about the DateFormatter to do this. In example 4, by handing out a value (not the invisible thread called a reference) it maintains it’s internal protection from corruption. Your lines of demarcation are safe.
Oh yes, the code is simpler too.
There just aren’t enough OO Fu points for this solution. This is OO Ninja.
yours, Marcus