Deep class composition and the Law of Demeter

600 views Asked by At

Evening. I'm having trouble finding an appropriate design pattern for some situations of deep composition. Let me present an example.

Let's say we have a class of type Corporation that has many classes of type Subsidiary that have many classes of type Department that in type contain many classes of type Unit that in turn contain many classes of type Employee.

Now, suppose the use case is to count the number of employees for each corporation. I could loop through each corpration, loop again for each subsidiary, and so on and so forth, in something that would result in a nested loop, 4 levels deep. Plus, I would be breaking the Law of Demeter by referencing my class chain several levels below, something that is so tightly couped it would break the very moment I modified my chain.

Another thing I could do is add tons (ok maybe not tons, but a few) of shortcut references. For example, a corporation could itself ALSO contain a list of Employees resulting in never having to walk through the chain to count them. This way, classes are less tightly coupled (but are they?) and the issue now becomes how to keep the Employee list synced for both the Corporation and the Unit. I could use the Observer pattern to keep them updated I suppose but I really feel something's horribly wrong with this idea or, at the very least, I'm not really using the best solution out there.

As I'm pretty sure this is an extremely common domain, could anyone be kind enough as to point me to an appropriate design pattern?

Thanks.

2

There are 2 answers

14
Narendra Pathai On

I don't exactly get the second question but I am answering the first question.

As the Law of Demeter states that each entity should have least knowledge about other units

So using that principle in your design

class Corporation{

    //All the stuff about corporation

    //Don't ask for what's inside corporation
    public int countEmployees(){
        //will apply the logic needed to calculate
    }

}

Better Client code with Law of Demeter:

corporationInstance.countEmployees(); //let the corporation handle how to count and not expose inner details

Without Law of Demeter

corporationInstace.getSubsidiaries().getSomethingElse()..... //exposing the inner details of class which creates a chain that is bad.

UPDATE:

Using the above stated solution you can go in as many depths as you want by creating the countEmployees() method inside Subsidiaries and in Unit as required. There is no point in breaking the encapsulation or using Observer pattern here.

Apply the Tell Don't ask principle as you have pointed in the comment yourself and delegate the responsibility of calculating the actual employees on the class that contains employees.

Department - > uses count method on subsidiaries to add their count
Subsidiaries - > uses Units to count
Unit - > Uses employees to count
0
fureszpeter On

Say you want to email the customer from a link or button. You might write it like customer.getSomeParticularContactInfo(addressType).sendEmail() or customer.sendEmail() which then (inside Customer) calls getSomeParticularContactInfo("primary").sendEmail().

You are on the wrong way. This breaks Single Responsibility, I mean, Customer Object doesn't need to know, how can send E-mail, Customer object is responsible only for how to provide the e-mail address belongs to the customer. So for this functionality, you need to create another Interface like Notifier and an EmailNotifier what implements Notifier. Thereafter you will call EmailNotifier.notify(customer)