Skip to main content

Value Design Pattern

Sometimes while you are coding, you need some kind of a wrap for some primitive data type such as an integer, just to add some feature that is not available directly from that primitive data type, or just to give it some identity.
A Date, Integer, or Dollar class is a handy - and inexpensive - encapsulation, easily copied, compared, or created when needed.
For example managing Bytes and printing them can be something annoying, for example, when ever you need to print the number of Bytes in a file, you would like to check if it can be represented in KB, MB, or GB.
So what I'm going to do here is to wrap the integer datatype into a Byte class, and override it's __toString function (one of the magic functions in PHP 5) so every time time I need to print it a simple print would do the issue.
Our example here would be for a mailbox, every mailbox has a quota, I want to give it a starting quota, then increase it, so first I'm going to write the Test for it (Using simpletest).

< ?php
// .... includes and stuff
class TestByte extends UnitTestCase {
function testQuotaByte () {
$this->UnitTestCase("Test Byte Value");
$startingQuota = new Byte(1048576); // One Mega
$mailbox1 = new MailBox($startingQuota);
$mailbox2 = new MailBox($startingQuota);
$this->assertEqual(1048576,$mailbox1->getQuota()->getBytes());
$this->assertEqual(1048576,$mailbox2->getQuota()->getBytes());
$mailbox1->increaseQuotaBy(new Byte(524288)); // add 512KB
$this->assertEqual(1572864,$mailbox1->getQuota()->getBytes());
$this->assertEqual(1048576,$mailbox2->getQuota()->getBytes());
$this->assertEqual(1048576,$startingQuota->getBytes());
}
}
$test = new TestByte();
$test->run(new HtmlReporter());
?>

Here I created to Mailboxes, and gave them a starting quota of 1 MB, after that I added 512 KB to one of them, and checked that it was added, and that the other mailbox and starting Quota was not changed.
Let's start with the implementation:

< ?php
class Byte {
protected $amount;
protected static $Names = array("B" => "B",
'KB' => 'KB',
'MB' => 'MB',
'GB' => 'GB',
'TB' => 'TB');
function __construct($bytes) {
$this-$gt;amount = $bytes;
}
public function add(Byte $bytes) {
$this->amount += $bytes->getBytes();
}
public function getBytes() {
return $this->amount;
}
public function getKB () {
return $this->amount/1024;
}
public function getMB () {
return $this->amount/1048576;
}
public function getGB() {
return $this->amount/1073741824;
}
public function getTB() {
return $this->amount/1099511627776;
}
public function __toString() {
if($this->getTB() >= 1) {
return number_format($this->getTB(), 2, '.', ' ')." ".self::$Names['TB'];
} elseif ($this->getGB() >= 1) {
return number_format($this->getGB(), 2, '.', ' ')." ".self::$Names['GB'];
} elseif ($this->getMB() >= 1) {
return number_format($this->getMB(), 2, '.', ' ')." ".self::$Names['MB'];
} elseif ($this->getKB() >= 1) {
return number_format($this->getKB(), 2, '.', ' ')." ".self::$Names['KB'];
} else {
return "$this->amount ".self::$Names['B'];
}
}
}
?>

and The Simple MailBox :

< ?php
class MailBox {
protected $quota;
function __construct(Byte $quota) {
$this->quota = $quota;
}
public function getQuota() {
return $this->quota;
}
public function increaseQuotaBy(Byte $addedQuota) {
$this->quota->add($addedQuota);
}
}
?>

OK Let's run the test.
TestByte
Fail: testQuotaByte -> Equal expectation fails because [Integer: 1048576] differs from [Integer: 1572864] by 524288 at [/some/Location/TestByte.php line 19]
Fail: testQuotaByte -> Equal expectation fails because [Integer: 1048576] differs from [Integer: 1572864] by 524288 at [/some/Location/TestByte.php line 21]
1/1 test cases complete: 3 passes, 2 fails and 0 exceptions.
What happened here? this code now points to ($this->assertEqual(1048576,$mailbox2->getQuota()->getBytes());) and ($this->assertEqual(1048576,$startingQuota->getBytes());) lines, Any Idea?
Here is a hint: in PHP 5 Objects are passed By Handle (Something like reference, yes similar to Java) not by value, is it clear now?
Another hint: They all point to the same Byte Object.
So actually changing one of them is changing them all.
So, how do you implement a lightweight, or easy to construct, descriptive object like Byte?
Lightweight objects should behave like PHP integers: if you assign the same object to two different variables and then change one of the variables, the other variable should remain unaffected. And indeed this is the goal of the Value Object pattern.So now we need to make the Byte Object immutable (i.e does not change once it's been set).
OK it's so Simple in our example, for the Byte class we change the add function to

< ?php
//...
public function add(Byte $bytes) {
return new Byte($this->amount + $bytes->getBytes());
}
//...
?>

also remember to change the MailBox class increaseQuotaBy function as now $quota is not changed in the add operation

< ?php
//...
public function increaseQuotaBy(Byte $addedQuota) {
$this->quota = $this->quota->add($addedQuota);
}
//...
?>

running the test
TestByte
1/1 test cases complete: 5 passes, 0 fails and 0 exceptions.
Viola!!, everything is cool.
Hope this article was useful.

Comments

Popular posts from this blog

اهم التطورات العلمية في العام ٢٠١٩

Dear Microsoft : It's over. Our relationship just hasn't been working for a while, and now, this is it. I'm leaving you for another Operating system. I know this isn't a good time--you're down with yet another virus. I do hope you feel better soon--really, I do--but I, too, have to move on with my life. Fact is, in the entire time I've known you, you seem to always have a virus or an occasional worm. You should really see a doctor. That said, I just can't continue with this relationship any longer. I know you say you'll fix things, that next time it'll go better--but that's what you said the last time--and the time before that. Each time I believed you. Well, not any longer. You cheater! The truth is there's nothing more you can say to make things better. I know about your secret marriage to patent. You say you two are not seeing each other anymore, but I just don't believe it. You say you can live without patent, and I've heard that

Saddam's novel to be published next week

AMMAN, Jordan: Saddam Hussein's family will publish next week a novel written by the ousted Iraqi leader before the US-led war on Iraq, his daughter said on Friday. "Ekhroj minha ya mal'un" whose title could be translated into "Get out, damned one" tells the story of a man called Ezekiel who plots to overthrow a town's sheik, but is defeated in his quest by the sheik's daughter and an Arab warrior. The story is apparently a metaphor for a Zionist-Christian plot against Arabs and Muslims. Ezekiel is meant to symbolize the Jews. Raghad Saddam Hussein said her father finished the novel on March 18, 2003 -- a day before the US-led war on Iraq began -- and had expressed a wish to publish the book under his name. The three other novels he wrote were simply signed "Its author." "It was my father's will to publish this book," Raghad said in a telephone interview. Read more An Iraqi artist designed the book's cover, she said, and a