I think you should not take decision on base of some sort of rumors. Sometimes composition is really good, but it require more code writing and more difficult in support (if you change BasicLight interface, you should manually change all dependent classes). Inheritance solve this problems, and some others. There are some cases when composition is preferable, but they appear mostly in complex projects.
OK, there are a few things to cover here.
First: why do you need to express commonality between PointLight
and Spotlight
? Is it
- Because there are clients who simply want to use them as a
Light
, and don't care which variety they get? - Because they share some implementation and you don't want to duplicate?
Because Clients need to treat Lights uniformly
This is Interface inheritance, also known as subtyping. Composition doesn't apply here - because there's nothing to compose. You can realise this in two ways: which you choose depends largely on your language.
- If you're using Java/C# this would usually be achieved by defining an Interface (
ILight
) that exposes all the common characteristics of Lights. Clients would depend only on the interface, not the implementations of it.PointLight
andSpotLight
would each implement the interface. - If you're not using a language with first class Interfaces, declare Light as an abstract base class with
PointLight
andSpotLight
inheriting from it.
Because you want to share implementation
There are generally two approaches to achieving this:
- Implementation inheritance. Define class
Light
and implement common behaviour in it. DeclarePointLight
andSpotLight
as inheriting fromLight
, overriding/adding behaviour as required. - Composition. Define classes
PointLight
andSpotLight
without inheriting from a common superclass. Implement a third class (which you'd still probably callLight
) that implements the common behaviour. BothPointLight
andSpotLight
would include an instance of 'Light` and delegate to it for the shared behaviour.
For your specific example there's relatively little to choose between Implementation inheritance and Composition. Issues with the former arise when the inheritance hierarchy gets deeper. It's also notoriously error prone in languages that support multiple implementation inheritance (e.g. the fragile base class problem). On the other hand, Implementation inheritance means less typing: the language autoamtically delegates to the shared behaviour, whereas with Composition you need to write the delegation methods.
Summary
Note also the above are not mutually exclusive: you could, for example:
- Declare an Interface
ILight
that bothSpotLight
andPointLight
implement - Share common behaviour using either implementation inheritance or composition
Fundamentally you need to be clear what you're trying to achieve.
hth.