Question

I've been reading about law of Demeter and I would like to know how to solve this traversing model properties problem that I see a lot on Objective-C. I know that there is a similar question but in this case I'm not calling a method from the last property that do some calculations, instead, I'm just setting values (Ok, I know that getter are methods but my intention here is just to get the value, not to change the state of some object).

For example:

self.priceLabel.text = self.media.ad.price.value;

Should I change that for something like:

self.priceLabel.text = [self.media adPriceValue];

and inside the Media.m

- (NSString *)adPriceValue {
    return [self.ad priceValue];
}

and inside the Ad.m

- (NSString *)priceValue {
    return [self.price value];
}

Is that a good solution? Or Am I creating unnecessary methods?

Was it helpful?

Solution

After reading the very interesting article posted by Robert Harvey, I'd suggest that if you're still worried about the LoD you do this (forgive me for not using ObjC syntax here, I have no clue how that works):

/* Old code: */
void update() {
  this.priceLabel.text = this.media.ad.price.value;
}

/* New code: */
void update() {
  updateAdInfo(this.media.ad);
}
void updateAdInfo(Ad ad) {
  // Can dive a level deeper here if you want to.
  this.priceLabel.text = ad.price.value;
}

Rationale: By introducing additional getters for sub-properties, you're flattening out your domain model, and that's just horrible: you lose all structure, and increase coupling. (What if you add a property to Ad? Do you now go to every single class that embeds an Ad and add getters for the new property?)

However, if you have a hierarchy of objects and a matching (partial) pseudo-hierarchy of view elements to display them, it makes sense to organize your update functions in a hierarchy as well.

OTHER TIPS

I suggest you consider the following.

  1. Does self need a reference to media and ad, or does self only use price? If you only use price, you don't need to go through the entire chain.

  2. If media.ad.price is primarily a data structure (little or no behavior/methods), you probably don't need to worry about Demeter.

  3. If self does use media, ad, and price, self might be complex enough to justify dividing self into smaller classes.

  4. There are trade-offs to hiding or exposing delegates. You should pick what you think works best for you, and it is possible to change your implementation later.

    Hiding the delegate forces you to write delegation methods, but it encapsulates changes to the structure. For example, if you add another layer, like media.ad.timeSlot.price, you would only have to change the delegate method, not all of the classes that use the delegate. On the other hand, as mentioned by Sebastian, if you want to add a new property or method for price, you have to write a delegation method.

  5. You can choose a middle-ground solution. For example, it might make sense for self to get a reference to ad, but add a method to ad to return the price value, so that self doesn't have to navigate the rest of the structure.

Licensed under: CC-BY-SA with attribution
scroll top