In an object-oriented system, component based design tends to be pretty straightforward.
First, you have a list of Component classes. These will probably derive from a base Component class that sets up the common interface and functionality for all components. These Component classes will tend to be concrete, rather than abstract. You won't have different types of Position component, for example: you will have just one. There's no reason for different objects to store position differently.
You then will have the Composition class (which often is just the same as your GameObject class, especially if you're only using component based design for game objects and not other parts of your engine architecture). At the simplest level, the Composition class is just a collection of Component objects. That's it. It has some helpers to add, remove, and query the Component objects stored in the container.
Your Component classes should be designed along useful functional boundaries. There is no reason to have a separate Position and Rotation component, for example. These are updated together by physics, they are access together by graphics, they are accessed together by game logic physics queries (ray casting, etc.). Just make a single Transform component that handles position, rotation, scale, and matrix generation. Making tons of smaller, "simpler" components will just mean that actually using your components will become a huge pain in the rear. Try to think of the things that you honestly don't need for every game object, or which need to be switched out and changed on a functional level for different game objects. The AI module in use is a good example. The physics model is NOT a good example, because a physics engine generally always uses the same concept of a Body and current physics states for all objects, and alters behavior based on data like mass, friction material, etc.
You should also avoid using code to decide what data can decide for you. DO NOT make one Component for enemies with 100 health and another for enemies with 1000 health. Likewise, from a code perspective, it doesn't matter in the slightest that undead monsters die at -100 and living ones don't; that's just a number. It's data. Use data to define those differences in your Health component, rather than different implementations of the component. You don't need a Health interface, because there is zero reason to ever have more than one implementation of the Health component. Different monsters will just have different MaxHealth and MinHealth member variables stored in the Health component, depending on when they die and what they start at. (Of course, replace MinHealth/MaxHealth with what variables make the most sense to you and solve your specific design problems).
If you rely entirely on components rather than data for design issues, you are not really buying yourself much. The entire point of component based design in games is that it allows rapid iteration and dynamic runtime composition of new and interesting behaviors. In other words, it allows data-driven composition of behavior. You need to embrace data-driven design. Anything and everything that you can pull out of code and put into a data file is a win. It means you can tweak values without recompiling. If you put a tiny bit of effort in, it means you can tweak values without even restarting the game or current level!
So far as dependency injection in particular, it is a natural part of using a component based design. It allows for your game object factory to create components as runtime from a file loaded from disk (e.g., a "blueprint" or "archetype" file). It allows you to entirely remove the concept of hard-coded classes like NPC or Ship or Bullet and instead use a data file to define what components those classes are made up. Or, if you want a hybrid approach, it would allow the object factory to decide from a data file which components to inject into your specific classes (NPC or Bullet, etc.) based on which blueprint data file was used to construct the object instance.
The flexibility there is that it lets you rapidly create new variations of a base class. Maybe you have Bullet with a ton of bullet-specific behavior. Now you can just define a bunch of different bullet types in a text file, and your game object factory can use composition to create instances of Bullet with those different configurations. The data file specifies the components and any data members for those components (e.g., the MinHealth/MaxHealth for the Health component). Then if you decide you want a new gun powerup for your Ship that fires a new kind of Bullet, you quite possibly don't need to edit a single line of code. You can create a Gun archetype, whose FireBullet component just has a data member that specifies which Bullet archetype it fiels. You have a new PowerUp archetype with a data member specifying which Gun it adds to your Ship. You have a new Bullet archetype that specifies the graphics parameters (texture, etc.) and any special physics logic and what kind of damage it does (either through components or through serialization support on your base Bullet object).
tl;dr version: data-driven design top to bottom, larger components split at functional boundaries, focus on what makes it easier to iterate your design and experiment with new ideas rather than on academic idealism (e.g., avoid "entity system" nonsense).