Traditional package managers have two distinct concepts: a repository and packages within those repositories.
For example, if ubuntu took down their apt repo server, I could run my own with all the same packages and change a single sources.list entry and all my servers, ansible roles installing packages, etc, would operate the same.
This is possible because the package name+version is an identifier everything else uses and the only thing that cares about the repository is apt itself; all other tooling doesn't need to know about the repository the package is sourced from.
Docker conflates those two things. Each client doesn't just send a package name, it sends a url + package name + version (e.g. foo.registryurl.com/image:version). Because every single client has the detail of "foo.registryurl.com" baked in, it's difficult to change that. I can't change a single "repository-mapping" file that the docker daemon reads to quickly update it.
Instead, I have to update every single client.
The idea of decoupling those is not new. In 2014 it was proposed [1], and various implementations that would help make it easier to migrate off the default registry have been proposed and rejected [2]
This doesn't even get into the lack of tooling for chasing down the transitive dependencies building my images has on various registries with each FROM.
[1]: https://github.com/moby/moby/issues/8329
[2]: https://github.com/moby/moby/pull/5821#issuecomment-49492924