What is it?
One of the object-oriented concepts, which frequently gets ignored (in my experience) is the process of using abstractions to premote loose coupling.
The "Stable Abstractions Principle" indicates that abstractness increases with stabilty and thus the more abstractions which are used, the more stable you application will be. So, with this in mind, it is a good idea to use abstractions whenever possible.
For instance, say you have an abstract class "Report". "Report" has one abstract method called "create_report".
Furthermore, "Report" has several sub-classes called "XmlReport", "TextReport", "HtmlReport" and "PdfReport". Obviously these sub-classes inherit from the super class "Report" and then override "create_report" with their version of how the report should be rendered.
Now, the code, which will be responsible for using the relevate reporting class, can be very general/abstract.
What Advantages Does This Have?
The advantage of this is the "report_type" parameter is abstract, so we can pass any of the sub classes of Report to the "print_report" method. To prove this, lets create an array of reports and pass them, one in turn, to the "print_report" method.
I am an Xml Report
I am a Text Report
I am a Html Report
I am a Pdf Report
I'm sure it is clear that changing "create_report" in any of the sub-classes i.e. XmlReport, TextReport... will have no effect on the "ReportGenerator" class. In addition to this, more types of reports can be created without making changes to "ReportGenerator". Simply inherit from "Report" and create a new class, say "YamlReport".