## Inversion of Control
"Inversion of control" is a design pattern used to allow users of a framework
or library (often called clients) to customize the behavior of the framework.
### Our Example
Examples in this document will be given by extending or modifying this example
API, which is hopefully self-explanatory:
```cpp
class StringKVStore {
public:
StringKVStore();
virtual ~StringKVStore();
using KeyPredicate = base::RepeatingCallback<bool(const string&)>;
void Put(const string& key, const string& value);
void Remove(const string& key);
void Clear();
string Get(const string& key) const;
set<string> GetKeys() const;
set<string> GetKeysMatching(const KeyPredicate& predicate) const;
void SaveToPersistentStore();
};
```
### What is inversion of control?
Normally, client code calls into the library to do operations, so control flows
from a high-level class to a low-level class:
```cpp
void YourFunction() {
// GetKeys() calls into the StringKVStore library
for (const auto& key : kv_store_.GetKeys()) {
...
}
}
```
In "inverted" control flow, the library calls back into your code after you
call into it, so control flows back from a low-level class to a high-level
class:
```cpp
bool IsKeyInteresting(const string& key) { ... }
void YourFunction() {
StringKVStore::KeyPredicate predicate =
base::BindRepeating(&IsKeyInteresting);
// GetKeysMatching() calls into the StringKVStore library, but it calls
// back into IsKeyInteresting defined in this file!
for (const auto& key : kv_store_.GetKeysMatching(predicate)) {
...
}
}
```
It is also often inverted in the Chromium dependency sense. For example, in
Chromium, code in //content can't call, link against, or generally be aware of
code in //chrome - the normal flow of data and control is only in one direction,
from //chrome "down" to //content. When //content calls back into //chrome, that
is an inversion of control.
Abstractly, inversion of control is defined by a low-level class defining an
interface that a high-level class supplies an implementation of. In the example
fragment given above, `StringKVStore` defines an interface called
`StringKVStore::KeyPredicate`, and `YourFunction` supplies an implementation of
that interface - namely the bound instance of `IsKeyInteresting`. This allows
the low-level class to use functionality of the high-level class without being
aware of the specific high-level class's existence, or a high-level class to
plug logic into a low-level class.
There are a few main ways this is done in Chromium:
* Callbacks
* Observers
* Listeners
* Delegates
**Inversion of control should not be your first resort. It is sometimes useful
for solving specific problems, but in general it is overused in Chromium.**
### Callbacks
Callbacks are one of the simplest ways to do inversion of control, and often are
all you need. Callbacks can be used to split out part of the framework's logic
into the client, like so:
```cpp
void StringKVStore::GetKeysMatching(const KeyPredicate& predicate) {
set<string> keys;
for (const auto& key : internal_keys()) {
if (predicate.Run(key))
keys.insert(key);
}
return keys;
}
```
where `predicate` was supplied by the client of
`StringKVStore::GetKeysMatching`. They can also be used for the framework
library to notify clients of events, like so:
```cpp
void StringKVStore::Put(const string& key, const string& value) {
...
// In real code you would use CallbackList instead, but for explanatory
// purposes:
for (const auto& callback : key_changed_callbacks_)
callback.Run(...);
}
```
making use of [Subscription].
Callbacks can also be used to supply an implementation of something deliberately
omitted, like so:
```cpp
class StringKVStore {
using SaveCallback = base::RepeatingCallback<void(string, string)>;
void SaveToPersistentStore(const SaveCallback& callback);
};
```
### Observers
An "observer" receives notifications of events happening on an object. For
example, an interface like this might exist:
```cpp
class StringKVStore::Observer {
public:
virtual void OnKeyChanged(StringKVStore* store,
const string& key,
const string& from_value,
const string& to_value) {}
virtual void OnKeyRemoved(StringKVStore* store,
const string& key,
const string& old_value) {}
...
}
```
and then on the StringKVStore class:
```cpp
class StringKVStore {
public:
...
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
}
```
So an example of a `StringKVStore::Observer` might be:
```cpp
class HelloKeyWatcher : public StringKVStore::Observer {
public:
void OnKeyChanged(StringKVStore* store,
const string& key,
const string& from_value,
const string& to_value) override {
if (key == "hello")
++hello_changes_;
}
void OnKeyRemoved(StringKVStore* store,
const string& key,
const string& old_value) override {
if (key == "hello")
hello_changes_ = 0;
}
}
```
where the `StringKVStore` arranges to call the relevant method on each
`StringKVStore::Observer` that has been added to it whenever a matching event
happens.
Use an observer when:
* More than one client may care to listen to events happening
* Clients passively observe, but do not modify, the state of the framework
object being observed
### Listeners
A listener is an observer that only observes a single type of event. These were
very common in C++ and Java before the introduction of lambdas, but these days
are not as commonly seen, and you probably should not introduce new listeners -
instead, use a plain [Callback].
Here's an example:
```cpp
class StringKVStore::ClearListener {
public:
virtual void OnCleared(StringKVStore* store) = 0;
}
```
Use a listener when:
* There is only a single client listener instance at most per framework object
* There is only a single event being listened for
### Delegates
A delegate is responsible for implementing part of the framework that is
deliberately missing. While observers and listeners are generally passive with
respect to the framework object they are attached to, delegates are generally
active.
One very common use of delegates is to allow clients to make policy decisions,
like so:
```cpp
class StringKVStore::Delegate {
public:
virtual bool ShouldPersistKey(StringKVStore* store, const string& key);
virtual bool IsValidValueForKey(StringKVStore* store,
const string& key,
const string& proposed_value);
};
```
Another common use is to allow clients to inject their own subclasses of
framework objects that need to be constructed by the framework, by putting
a factory method on the delegate:
```cpp
class StringKVStore::Delegate {
public:
virtual unique_ptr<StringKVStoreBackend>
CreateBackend(StringKVStore* store);
}
```
And then these might exist:
```cpp
class MemoryBackedStringKVStoreDelegate : public StringKVStore::Delegate;
class DiskBackedStringKVStoreDelegate : public StringKVStore::Delegate;
...
```
Use a delegate when:
* There needs to be logic that happens synchronously with what's happening in
the framework
* It does not make sense to have a decision made statically per instance of a
framework object
### Observer vs Listener vs Delegate
If every call to the client could be made asynchronous and the API would still
work fine for your use case, you have an observer or listener, not a delegate.
If there might be multiple interested client objects instead of one, you have an
observer, not a listener or delegate.
If any method on your interface has any return type other than `void`, you have
a delegate, not an observer or listener.
You can think of it this way: an observer or listener interface *notifies* the
observer or listener of a change to a framework object, while a delegate usually
helps *cause* the change to the framework object.
### Callbacks vs Observers/Listeners/Delegates
Callbacks have advantages:
* No separate interface is needed
* Header files for client classes are not cluttered with the interfaces or
methods from them
* Client methods don't need to use specific names, so the name-collision
problems above aren't present
* Client methods can be bound (using [Bind]) with any needed state, including
which object they are attached to, so there is no need to pass the framework
object of interest back into them
* The handler for an event is placed in object setup, rather than being implicit
in the presence of a separate method
* They sometimes save creation of "trampoline" methods that simply discard or
add extra parameters before invoking the real handling logic for an event
* Forwarding event handlers is a lot easier, since callbacks can easily be
passed around by themselves
* They avoid multiple inheritance
They also have disadvantages:
* They can lead to deeply-nested setup code
* Callback objects are heavyweight (performance and memory wise) compared to
virtual method calls
### Design Tips
1. Observers should have empty method bodies in the header, rather than having
their methods as pure virtuals. This has two benefits: client classes can
implement only the methods for events they care to observe, and it is
obvious from the header that the base observer methods do not need to be
called.
2. Similarly, delegates should have sensible base implementations of every
method whenever this is feasible, so that client classes (subclasses of the
delegate class) can concern themselves only with the parts that are
relevant to their use case.
3. When inverting control, always pass the framework object of interest back to
the observer/listener/delegate; that allows the client, if it wants to, to
reuse the same object as the observer/listener/delegate for multiple
framework objects. For example, if ButtonListener (given above) didn't pass
the button in, the same ButtonListener instance could not be used to listen
to two buttons simultaneously, since there would be no way to tell which
button received the click.
4. Large inversion-of-control interfaces should be split into smaller
interfaces when it makes sense to do so. One notorious Chromium example
is [WebContentsObserver], which observes dozens of different events.
Whenever *any* of these events happens, *every* registered
WebContentsObserver has to be notified, even though virtually none of them
might care about this specific event. Using smaller interfaces helps with
this problem and makes the intent of installing a specific observer clearer.
5. The framework class *should not* take ownership of observers or listeners.
For delegates the decision is less clear, but in general, err on the side of
not taking ownership of delegates either. It is common to hold raw pointers
to observers and listeners, and raw or weak pointers to delegates, with
lifetime issues managed via AddObserver/RemoveObserver or the helper classes
discussed below.
6. Depending on your application and how widely-used you expect your observer,
listener, or delegate to be, you should probably use names that are longer
and more specific than you might otherwise. This is because client classes
may be implementing multiple inversion-of-control interfaces, so it is
important that their method names not collide with each other. For example,
instead of having `PageObserver::OnLoadStarted`, you might have
`PageObserver::OnPageLoadStarted` to reduce the odds of an unpleasant
collision with `NetworkRequestObserver::OnLoadStarted` (or similar). Note
that callbacks entirely avoid this problem.
7. A callback is probably a better fit for what you're trying to do than one
of the other patterns given above!
### Inversion of Control in Chromium
Some key classes in `//base`:
* [base::ScopedObservation]
* [ObserverList] and [CheckedObserver]
* [Subscription] and [CallbackList]
And some production examples:
* [WebContentsObserver] and [WebContentsDelegate]
* [BrowserListObserver]
* [URLRequestJobFactory::ProtocolHandler]
* [WidgetObserver] and [ViewObserver]
### When Not To Use This Pattern
Inverted control can be harder to reason about, and more expensive at runtime,
than other approaches. In particular, beware of using delegates when static data
would be appropriate. For example, consider this hypothetical interface:
```cpp
class StringKVStore::Delegate {
virtual bool ShouldSaveAtDestruction() { return true; }
}
```
It should be clear from the naming that this method will only be called once per
StringKVStore instance and that its value cannot meaningfully change within the
lifetime of a given instance; in this case, "should save at destruction" should
instead be a parameter given to StringKVStore directly.
A good rule of thumb is that any method on a delegate that:
* Will only be called once for a given framework object, or
* Has a value that can't meaningfully change for a given framework object, and
* Serves primarily to return that value, rather than doing some other work
like constructing a helper object
should be a property on the framework object instead of a delegate method.
[Bind]: ../../base/functional/bind.h
[BrowserListObserver]: ../../chrome/browser/ui/browser_list_observer.h
[CallbackList]: ../../base/callback_list.h
[Callback]: ../../base/functional/callback.h
[CheckedObserver]: ../../base/observer_list_types.h
[ObserverList]: ../../base/observer_list.h
[base::ScopedObservation]: ../../base/scoped_observation.h
[Subscription]: ../../base/callback_list.h
[URLRequestJobFactory::ProtocolHandler]: ../../net/url_request/url_request_job_factory.h
[Unretained]: ../../base/functional/bind.h
[ViewObserver]: ../../ui/views/view_observer.h
[WebContentsDelegate]: ../../content/public/browser/web_contents_delegate.h
[WebContentsObserver]: ../../content/public/browser/web_contents_observer.h
[WidgetObserver]: ../../ui/views/widget/widget_observer.h