The simplest texture manager has one function: GetTexture. GetTexture checks its cache for a texture. If the texture isn't cached, it loads the texture. Then it returns the texture. Kapow! Done!
That is sufficient for most small-scale indie games I've seen. You just don't have enough content for this to ever be a problem.
One downside is that this can result in loading hiccups during gameplay. Quick fix: just call GetTexture with all the textures you expect to use during a "loading" section. Another possible fix: when you "load" a texture, hand a functional blank texture handle back, then start loading in the data asynchronously in the background (in another thread or with asynchronous file loading calls) and fill it in once it's done. This way you avoid the load hitches, but things can look a bit weird until textures are filled in. If you want to implement this, I'd recommend a GetTextureAsync function to call when asynchronous loading is acceptable (which in my experience will be only a few places, but those places may account for the majority of the textures in your game.)
Another downside is that you will, eventually, keep all the textures in your game in memory at once. This can also be easy to fix - if your game is divided into levels, just clear the entire cache between levels and reload everything. A somewhat more complex solution is to throw away textures after they've been unused for some number of seconds. This works great for large streaming worlds with unknown resources needed at each point (like MMOs - you never know what armor you're going to see next) but it does mean there's some lag between when a texture is unneeded and when the memory is actually freed.
If you want a more complex texture manager, you can start having formal concepts of blocks of textures that need to be preloaded. Each level can have a texture corpus, and when you change levels, you explicitly throw away the old corpus and load in the new one. Couple this with on-demand loading for unexpected textures, and a delay for deallocating those, and you're pretty much set for quiet some time.
As an example of this, in a game in a large contiguous world you might break the world into areas, then come up with a corpus for each area. Load textures for all adjacent areas to the player while throwing away textures from further away. (With refcounting, of course - if every area uses "grass", then there's no reason to store multiple copies of "grass".)
But meanwhile, back in reality, you'll probably be just fine with GetTexture. :)