Interfaces
It's hard to understand the purpose of a tool that solves a problem that you've never had. I didn't understand interfaces for a while after I started programming. We'll I understood what they did, but I didn't know why you'd want to use one.
Here's the problem - you know what you want to do, but you have multiple ways to do it, or you may change how you do it later. It would be nice if you could play the role of the clueless manager - bark some orders and have the results you want without caring about how it's done.
Say you have a tiny little website, and you save all of your users' info in a csv file. Not the most sophisticated solution, but it works well enough to store your mom's user details. Later, your site takes off and you have 10,000 users. Maybe it's time to use a proper database.
If you were clever at first, you would have seen this coming and not made the calls to save to csv directly. Instead you'd think of what you needed it to do, no matter how it was implemented. Let's say store()
and retrieve()
. You make a Persister
interface with abstract methods for store()
and retrieve()
and create a CsvPersister
subclass that actually implements those methods.
Later, you can create a DbPersister
that implements the actual storage and retrieval of data completely differently from how your csv class did it.
The great thing is, all you have to do now is change
Persister* prst = new CsvPersister();
to
Persister* prst = new DbPersister();
and then you're done. Your calls to prst.store()
and prst.retrieve()
will all still work, they're just handled differently "behind the scenes".
Now, you still had to create the cvs and db implementations, so you haven't experienced the luxury of being the boss yet. The real benefits are apparent when you're using interfaces that someone else created. If someone else was kind enough to create a CsvPersister()
and DbPersister()
already, then you just have to pick one and call the necessary methods. If you decide to use the other one later, or in another project, you already know how it works.
I'm really rusty on my C++, so I'll just use some generic programming examples. Containers are a great example of how interfaces make your life easier.
You can have Array
, LinkedList
, BinaryTree
, etc. all subclasses of Container
which has methods like insert()
, find()
, delete()
.
Now when adding something to the middle of a linked list, you don't even have to know what a linked list is. You just call myLinkedList->insert(4)
and it magically iterates through the list and sticks it in there. Even if you know how a linked list works (which you really should), you don't have to look up its specific functions, because you probably already know what they are from using a different Container
earlier.
Abstract Classes
Abstract classes are pretty similar to interfaces (well technically interfaces are abstract class, but here I mean base classes that have some of their methods fleshed out.
Say you're creating a game, and you need to detect when enemies are within striking distance of the player. You could create a base class Enemy
that has a method inRange()
. Although there are many things about the enemies that are different, the method used to check their range is consistent. Therefore your Enemy
class will have a fleshed out method for checking range, but pure virtual methods for other things that share no similarities amongst the enemy types.
The nice thing about this is if you mess up the range detection code or want to tweak it, you only have to change it in one place.
Of course there are many other reasons for interfaces and abstract base classes, but those are some reasons why you might use them.
Singletons
I use them occasionally, and I've never been burned by them. That's not to say they won't ruin my life at some point, based on other peoples' experiences.
Here's a good discussion on global state from some more experienced and wary folks:
Why is Global State so Evil?