The modern consensus is that you should not do this at all.
Having a 'all instances of this class' design has proven to be troublesome in many aspects, the foremost being with regards to concurrency. Do you want all widgets, or all widgets owned by your thread? Do you really want to make that all widget list threadsafe? Remember that unit tests are almost always done in parallel, so "my app is single threaded" might not be good enough.
The other problem you run into is in your design. With the 'one and only' list of anything, be it global, static or singleton you'll quickly run into issues when you need more than one. You'll run into issues with temporary widgets or offscreen widgets if they're automatically added to the list. You'll run into errors where you forgot to add them to the list if they're not automatically handled.
Once you don't have the 'all instances of a class' requirement, then you end up with a plain old collection. Whatever consuming code is working with the widgets (even if that's some framework that is in turn consumed) can orchestrate how the collection is used and how/when the widgets get put in there. The widgets themselves should not care.
There are two ways I could code this:
The first way is to create getters (i.e. houses, streets, suburbs) and select / deselect recipients that way.: messageRecipients.streets.select(aStreet).
Don't think I prefer this way but I don't want to see the Law of Demeter misapplied.
Some think this is all LoD has to say:
the Law of Demeter for functions requires that a method m of an object O may only invoke the methods of the following kinds of objects:
- O itself
- m's parameters
- Any objects created/instantiated within m
- O's direct component objects
- A global variable, accessible by O, in the scope of m
In particular, an object should avoid invoking methods of a member object returned by another method. For many modern object oriented languages that use a dot as field identifier, the law can be stated simply as "use only one dot". That is, the code a.b.Method() breaks the law where a.Method() does not. As an analogy, when one wants a dog to walk, one does not command the dog's legs to walk directly; instead one commands the dog which then commands its own legs.
Wikipedia: Law of Demeter
This is a monument to structural thinking. There is not a single semantic or conceptual thought in any of that. A static analyzer could enforce this. Bleh. This is not all I think of when I think of the LoD.
The Law of Demeter is not a dot counting exercise.
When you are an object, it is better to only talk to your friends, not friends of friends. If you randomly pull in anything you happen to need you'll soon find you've pulled together so many things that any change to the code base is going to hurt you right here.
Friends are things whose interfaces you own. Only then are you promised that you could jump through these dots and always find the same thing. While that can happen it's not going to be true if you just randomly grab whatever you like out of a code base.
So if the client calling "messageRecipients.streets.select(aStreet)" owns the interface for messageRecipients
and streets
then it's talking to its friends and there is no LoD violation. This means the client owns all the interfaces it uses. They should not change without the client's permission. This should be made clear to maintenance programmers. This needs clear boundaries. But it's not about dot counting.
That's the real problem. Because of the way you're getting this other object, the dependence on it's interface isn't explicit. The dependence can be a surprise. If you respect that you'll find some way to make this dependence clear to other coders.
This shouldn't be some cobbled together situation. This should be a situation created by careful design. What's being created here actually has a name. It's called a DSL. If that's what you're making fine. If this is just some randomly thrown together stuff because you happened to need it then you're creating a problem waiting to happen.
The other name the LoD goes by is "the principle of least knowledge". It's asking you to understand that when you create these dot chains you're adding knowledge to your client not only of these interfaces but how they connect. The more you know the more it hurts when things change. Don't create chains no one promised would be stable.
The other way would be to hide the fact that MessageRecipients is using SelectableEntity at all and simple create 'proxy' methods for each method on SelectableEntity (i.e. selectHouse, deselectHouse, selectStreet, etc).
I like this idea, but i'd also hide whether what's being selected is a house, street, or suburb. Let the suburb be the only thing that cares that it's a suburb.
Best Answer
In many programming languages, all returned values are objects. As others have said, not being able to use the methods of returned objects forces you to never return anything at all. You should be asking your self, "What are the responsibilities of class A, B and C?" This is why using metasyntactic variable names like A, B and C always solicit the answer "it depends" because there is no inherit responsibilities in those terms.
You may want to look into Domain Driven Design, which will give you a more nuanced set of heuristics to reason about where functionality should go and who should be invoking what.
Your second question concerning immutable objects speaks to the notion of a
Value Object compared to an Entity object. in DDD, You can pass value objects around with almost no restrictions. This does not speak true for entity objects.
The simplistic LOD is much better expressed in DDD as the rules for accessing Aggregates. No external objects should hold references to members of aggregates. Only a root reference should be held.
DDD aside, you at least want to develop your own sets of stereotypes for your classes that are reasonable for your domain. Enforce rules about those stereotypes as you design your system.
Also always remember that all of these rules are to manage complexity, not to hamstring yourself.