There are a lot of services within Wikibase that can have one implementation per entity type. Wikibase uses type dispatching services to delegate to the service corresponding to the object (an entity or an entity id) that is passed in as an argument. See e.g. [TypeDispatchingEntityTitleStoreLookup](https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/Wikibase/+/0a476751ca7a91d66df554a0f5824387f3854d53/repo/includes/Store/TypeDispatchingEntityTitleStoreLookup.php).
Many of the services are very similar and repeat the same couple of lines of code, but very few of them share code. Only recently some of the shared functionality [was extracted](https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Wikibase/+/595868) from services introduced within the federated properties hike. This extracted `ServiceByTypeDispatcher` only fit the few use cases that it was created for initially, but can likely be extended to cover many more. For some of the existing type dispatching services it is obvious what needs to be changed either in `ServiceByTypeDispatcher` or in the dispatching service itself to make the two fit together, others use completely different patterns.
These services are used all over the code base and they all do pretty much the same thing, but implemented in sometimes subtly, sometimes completely different way. This makes them difficult to maintain. Chances are that they could be much more uniform.
A few patterns that emerged when looking through the list of existing type dispatching services:
* dispatchers that themselves implement the interface of the services they delegate to, and create and cache services per entity type at the time one of the interface methods are called e.g. TypeDispatchingEntityTitleStoreLookup, TypeDispatchingArticleIdLookup, ...
* factories that create the required service based on the entity type e.g. DispatchingEntityMetaTagsCreatorFactory, EntityLinkFormatterFactory, ...
* registering different strategies to dispatch to, e.g. EntityPatcher, EntityDiffer, ...
The following is a list of dispatching services (based on their EntityTypeDefinitions constants) and whether they can be changed to also use the new type dispatcher:
**Already use ServiceByTypeDispatcher **
* ARTICLE_ID_LOOKUP_CALLBACK
* TITLE_TEXT_LOOKUP_CALLBACK
* URL_LOOKUP_CALLBACK
* EXISTENCE_CHECKER_CALLBACK
* REDIRECT_CHECKER_CALLBACK
**Can probably use ServiceByTypeDispatcher**
* ENTITY_ID_LOOKUP_CALLBACK https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Wikibase/+/599056
**Can probably use ServiceByTypeDispatcher once it supports arguments on the factory callbacks**
* ENTITY_TITLE_STORE_LOOKUP_FACTORY_CALLBACK
* ENTITY_STORE_FACTORY_CALLBACK
* ENTITY_REVISION_LOOKUP_FACTORY_CALLBACK
* ENTITY_DIFF_VISUALIZER_CALLBACK (EntityDiffVisualizerFactory)
* CHANGEOP_DESERIALIZER_CALLBACK (EntityChangeOpProvider)
* LINK_FORMATTER_CALLBACK (EntityLinkFormatterFactory)
**Can probably use ServiceByTypeDispatcher once it can be used without a default**
* VIEW_FACTORY_CALLBACK
**Cannot use ServiceByTypeDispatcher without major changes**
* ENTITY_METADATA_ACCESSOR_CALLBACK
** the way it's currently implemented, it must not cache the implementation because it depends on the language at construction time
** can probably be made to use ServiceByTypeDispatcher by passing the language into the method instead
* META_TAGS_CREATOR_CALLBACK
** same as above
* PREFETCHING_TERM_LOOKUP_CALLBACK
** `ByTypeDispatchingPrefetchingTermLookup` dispatching via instances of PrefetchingTL instead of factory callbacks
* SERIALIZER_FACTORY_CALLBACK
** use `isSerializerFor` to determine the right serializer for entities
* STORAGE_SERIALIZER_FACTORY_CALLBACK
** same as above but can probably be changed into the usual pattern
* DESERIALIZER_FACTORY_CALLBACK
** use a similar pattern to SERIALIZER_FACTORY_CALLBACK
* ENTITY_DIFFER_STRATEGY_BUILDER
** same as above, but can likely be changed
* ENTITY_PATCHER_STRATEGY_BUILDER
** samve as above
* ENTITY_SEARCH_CALLBACK
** similarly to ENTITY_METADATA_ACCESSOR_CALLBACK it is constructed in a way that does not allow for it to be cached
* ENTITY_ID_HTML_LINK_FORMATTER_CALLBACK
** are built all at once and passed into DispatchingEntityIdHtmlLinkFormatter as instances instead of callbacks but that's probably unnecessary
* ENTITY_REFERENCE_EXTRACTOR_CALLBACK
** has some extra default behavior in the dispatcher, could be converted
**Unclear**
* CONTENT_HANDLER_FACTORY_CALLBACK
** ContentHandlerFactory could possible use ServiceByTypeDispatcher
* RDF_BUILDER_FACTORY_CALLBACK
** all created at once in EntityRdfBuilderFactory - not sure if by design
* SEARCH_FIELD_DEFINITIONS
** the way it's used makes me question whether it's useful at all