First of, what we discuss here is the OOP way of doing things, and that in a manner with respect to the mid to long run. It is just an approach to defeat problems that may occur in the future when software should be extended or reworked in some way. There is no constraint to follow it absolutely; software worked also before OOP was invented. In the end software development ever suffers from demand for high quality but low effort. But without being sensitive to the danger of what may happen when software grows, bad things will happen.
EDIT
I should perhaps highlight that XML and binary, as long as used by me, is meant not as generic but as specific file format, i.e. "my game's specialized XML file format" and "my game's specialized binary file format".
/EDIT
1. Are you saying the ResourceManager should call a ResourceLoader? If so, is ResourceLoader split into "XMLResourceLoader" and "BinaryResourceLoader"?
Again; if so, why not just have a "loadXML()" and "loadBinary()" functions inside ResourceLoader? Is that what the bad thing is?
Yes, I mean that if the ResourceManager object has determined that a specific resource requested by a client is not available from the cache and hence need to be loaded, it delegates the loading to a ResourceLoader object.
How the ResourceLoader class works is another question. It could be an abstract base class, and XMLResourceLoader and BinaryResourceLoader are classes derived by inheriting ResourceLoader. So ResourceLoader provides the common API used by ResourceManager, and XMLResourceLoader and BinaryResourceLoader each one implement the interface, regarding of loading from an XML or binary source, respectively.
Is the ResourceManager free to make the distinction whether to use the one or other subtype of ResourceLoader? No, because the format of the data source defines which loader type is to be used, because one cannot use e.g. BinaryResourceLoader to read from an XML source. If ResourceLoader would publicly provide loadXML() and loadBinary(), the choice of what to use would be externalized, although one and only one of them will work anyway. But if ResourceLoader (i.e. the base class) provides a single abstract load() function, the ResourceManager has no need to know whether the source is XML or binary (or whatever else); it just invokes load() on the concretized ResourceLoader that is available to load the resource.
2. Should ResourceManager have all the ResourceContainers (which then contain Resource objects)?
[...]
The manager should have all containers that are needed to manage the resource types the manager is responsible for. I used this "weak" sentence because you may find it useful to manage resources for each game level separately, or (which means an inclusive or) you may find it useful to manage resources separated by type.
[...]
Should ResourceManager even call ResourceLoader?
In this discussion we use ResourceManager like a director. The manager knows of the loader, cache, ... and mediates between them; that is its job. When going this route, then there is no need to couple e.g. the ResourceLoader to the ResourceContainer just for the purpose to enable the loader to store the resource directly. The ResourceManager, on the other hand, is coupled to the ResourceContainer anyway, because it needs to check whether a resource is already loaded before wasting time by calling a loader.
Notice that the responsibility of ResourceLoader is to load a requested resource. Whether it is meaningful to load it and what happens to the resource after loading is out of the scope of the loader. Restricting the responsibility like so makes it easier to re-use the classes in other contexts. That is one of the points of maintainability.
3. Do you mean that the Sprite class should not have functions to write/read buffers? If so, do you mean there should be a SpriteSerializer class?
Serializing an object means to transform its data into an external representation. In other words, a specific format is used. But the format can change (e.g. XML vs. binary, or version evolution). To abstract this, we have ResourceLoader (and ResourceWriter if saving is supported). So SpriteSerializer would just be another concretization of ResourceWriter.
Notice please that a sprite (as example for any resource) is just a typed data container including some metadata. The animation sub-system alters its world transform, the graphic renderer reads it for the purpose of rendering, the resource loader is able to write data to it, and so on. The sprite itself, as a resource, does almost nothing by itself. If you want to support ResourceLoader / ResourceWriter directly from the resource, then at most something like the Memento pattern should be used.
Some more things to think about:
You have probably noticed that the loader classes so far are designed to abstract the format of the data source, ignoring the type of resource. (BTW: Here the XMLResourceLoader is not meant to understand XML files in general but XML files formatted to represent your game resources, of course.) Real world file formats often represent a single type of resource (see PNG, JPG, WAV, OBJ, ...). In such cases the concrete ResourceLoader (e.g. PngResourceLoader) is a-priorily defined to result in a specific resource type. But in cases of games we often deal with file formats that provide collections of resources (a.k.a. package files or archive files). So, if you want to support single resource loading, you need to support the internal directory that is inherent to such collections. This can be solved by implementing the concrete ResourceLoader to handle the collection stuff and to revert to other concrete ResourceLoader instances as soon as the type of the resource is determined.
Further, we have not examined the dimension of data sources. So far we load resources from files. That is fine in general because files are already abstractions, since they may be mass storage based or socket based. If ResourceLoader should be agnostic of what kind of file it is dealing with, the file has to be opened external to the ResourceLoader class. IMHO even better, any ResourceLoader should deal with an abstraction DataSource anyway.