1 Star2 Stars3 Stars4 Stars5 Stars (4 votes, average: 4.00 out of 5)
Loading ... Loading ...

Low coupling

When designing some architecture, you face with the problem “which object should perform X task?” We discussed this question in my previous post in this series. There we noted, that object should perform the tasks he has enough info for. He should be an “expert”. But because one of the main OOP characteristics is interaction between objects, it’s often hard to answer this question.

Introducing example

Consider you should print the table parameters (see What is OOP post for this example). There are tables of 2 types: square and circle ones. Square has parameter “side”, circe has parameter – “radius”. And we need the table:

Tables list

Tables list


Sure, we can create a class Lister and method Lisert::out(). But what logic to place there? We can go with something like this:

  1.  
  2. <?php
  3. class Lister
  4. {
  5.         public $tables;
  6.  
  7.     public function out()
  8.         {
  9.                 echo "+———-+———–+———+
  10. |  Type    | parameter |  value  |
  11. +———-+———–+———+\n";
  12.                 for ($i = 0, $s = sizeof($this->tables); $i < $s; $i++)
  13.                 {
  14.                         if ($this->tables[$i] instanceof CircleTable)
  15.                         {
  16.                                 echo ‘|  Circle  |  radius   |  ’.sprintf(‘%5.2f’, $this->tables[$i]->radius)."  |\n";
  17.                         }
  18.                         else
  19.                         {
  20.                                 echo ‘|  Square  |  side     |  ’.sprintf(‘%5.2f’, $this->tables[$i]->side)."  |\n";
  21.                         }
  22.                         echo "+———-+———–+———+\n";
  23.                 }
  24.         }
  25. }
  26. ?>
  27.  

Identifying the problem

However, this method is strictly linked to using only CircleTable and SquareTable, it will not work without CircleTable and adding other table types is impossible. This can be imagined like this:

Classes coupling

Classes coupling


Notice that since Lister class uses CircleTable and SquareTable, they can’t be used along. This picture illustrates it – they are coupled together.

Coming up with a solution

The correct variant of solving the task of table output is the following.

  1. Refactor Table classes putting the output logic, that is specific to the table into the class
  2. Use these new methods of table classes in the Lister::out method

Enough talk, let’s walk!

  1.  
  2. class CircleTable extends Table
  3. {
  4.         public $radius;
  5.  
  6.         public function __construct($r, $h)
  7.         {
  8.                 parent::__construct($h);//calling the constructor of the parent class, passing height there.
  9.                 $this->radius = $r;//setting the radius
  10.         }
  11.  
  12.         public function getSquare()
  13.         {
  14.                 return $this->radius*$this->radius*M_PI;
  15.         }
  16.  
  17.         public function out()
  18.         {
  19.                 echo ‘|  Circle  |  radius   |  ’.sprintf(‘%5.2f’, $this->radius)."  |\n";
  20.         }
  21. }
  22.  
  23. class SquareTable extends Table
  24. {
  25.         public $side;
  26.  
  27.         public function __construct($s, $h)
  28.         {
  29.                 parent::__construct($h);//calling the constructor of the parent class, passing height there.
  30.                 $this->side = $s;//setting the side
  31.         }
  32.  
  33.         public function getSquare()
  34.         {
  35.                 return $this->side*$this->side;
  36.         }
  37.  
  38.         public function out()
  39.         {
  40.                 echo ‘|  Square  |  side     |  ’.sprintf(‘%5.2f’, $this->side)."  |\n";
  41.         }
  42. }
  43.  

And we’ll use these methods in the Lister class:

  1.  
  2. class Lister
  3. {
  4.         public $tables;
  5.  
  6.     public function out()
  7.         {
  8.                 echo "+———-+———–+———+
  9. |  Type    | parameter |  value  |
  10. +———-+———–+———+\n";
  11.                 for ($i = 0, $s = sizeof($this->tables); $i < $s; $i++)
  12.                 {
  13.                         $this->tables[$i]->out();
  14.                         echo "+———-+———–+———+\n";
  15.                 }
  16.         }
  17. }
  18.  

Running the code with the same data will give us exactly the same thing. But only one difference – this code is easy to maintain, change and expand. We can imagine this structure as following:

Low coupling illustration

Low coupling illustration


For example, if we need one more table – triangle – we just add this class and then – created object into the List::tables property and that’s all. It will be printed out.
Here is the code:

  1.  
  2. class TriangleTable extends Table
  3. {
  4.         public $side;
  5.  
  6.         public function __construct($s, $h)
  7.         {
  8.                 parent::__construct($h);//calling the constructor of the parent class, passing height there.
  9.                 $this->side = $s;//setting the side
  10.         }
  11.  
  12.         public function getSquare()
  13.         {
  14.                 return $this->side*$this->side*0.433;
  15.         }
  16.  
  17.         public function out()
  18.         {
  19.                 echo ‘| Triangle |   side    |  ’.sprintf(‘%5.2f’, $this->side)."  |\n";
  20.         }
  21. }
  22.  

And now add this table to the test script:

  1.  
  2. <?php
  3. require_once(‘Table.php’);
  4. require_once(‘Lister.php’);
  5. $list = new Lister();
  6. $list->tables = array(
  7.         new CircleTable(5, 90),
  8.         new SquareTable(2, 85),
  9.         new SquareTable(8, 100),
  10.         new TriangleTable(7,150),
  11.         new TriangleTable(10,120),
  12. );
  13. header(‘Content-type: text/plain’);
  14. $list->out();
  15. ?>
  16.  

And we’ll get the following table with no modifications in the Lister class:

Modified list of tables

Modified list of tables


Note, that we can populate tables list from the DB table and no code will be changed. Adding new table type is very simple – you just develop the class similar to CircleTable or SquareTable and then use it. No more changes needed.
This technique when you do your best to write the isolated pieces of code, which can be reused separately is called “Low Coupling”, your goal is to create classes in such a way that they do not depend on each other or check these dependencies preventing runtime errors.
Sure, that’s the goal, it can’t be achieved in full, but you should aim to do this.

High cohesion

When you do your best to implement the Lout Coupling principle, you write your code in a small portions, and each of them does some definite task. And since each class is small and does only one or several cohesive jobs, you get High Cohesion in your code.
These two principles go together. When you fulfil one of them, you automatically follow another one.

Summary

Putting it all together, we may say that Low Coupling principle requires writing isolated pieces of code, that form complex logic only by interacting with each other, not by themselves. And While following this principle, our little parts automatically become focused on one task, so they become cohesive. This way we fulfil both principles at once.
And good OO-design follow all GRASP principles at the same time just because they characterise nice application design.

What can you add here? Maybe you’ve got some questions? Feel free to ask here in comments or by email.
Grab the code of examples here.

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

Share this post with a friend Share this post with a friend

One Comment

  1. hitesh says:

    Nice explanation. It will help !

Leave a Reply