Extract BaseHookCollection

Previously the HookCollection was acting as a base with the subclasses
overriding (some) methods. With this change, each subclass extends the
base class by adding new methods, not overriding existing ones. Makes it
all a bit easier to reason about.