Another method that goes a little further and is a little more sane in the future might be to drop SpecialPages, Actions, Article, and {Category,Image,etc...}Page classes and replace them with one set of classes in charge of building page outputs and a system that uses rules to determine what class should handle the page.
Basically instead of the top level Article, top level SpecialPage, and top level Action that each work in a different way we would instead have one abstract top level PageView that works in one way. Everything that previously existed as something else would be replaced with a PageView subclass. Common traits and patterns would become abstract subclasses of PageView that would be subclassed instead of PageView directly.
A router would pick the right PageView to use for a specific request with rules loaded into it like:
- (title) + (action = edit) -> EditPageView
- (title = Special:Edit) -> EditPageView
- (title) + (action = history) -> HistoryPageView
- (title = Special:History) -> HistoryPageView
- ...
- (title = Special:Whatlinkshere) -> WhatlinksherePageView
- (title) + (action = whatlinkshere) -> WhatlinksherePageView (?)
- ...
- (title = Special:Block) -> BlockPageView
- ...
- (title ns Category:) -> CategoryPageView
- (title ns File:) -> FilePageView
- ...
- (title) -> ArticlePageView
- (title) + (action = view) -> ArticlePageView
- ...
- (title ns Special:) -> LegacySpecialPageView
- (title) + (action) -> LegacyActionPageView
- () = NoPageView (generic 404 or mainpage redirect) (?)
Things like EditPageView, HistoryPageView, and WhatlinksherePageView would subclass a TitlePageView to provide title targeting. And others like BlockPageView would subclass a UserPageView to provide user targeting.
Various parts of the rules could be tied to the i18n system. ie: The special page name translations could easily be added in. (Though I wight want to have that name mapping setup generalized to apply to other things).
Extensions could even take over things in ways they could never do before. For example a "(title ns Thread:) + (action = history)" rule could be used to replace the history page view completely for a specific namespace.