IntroductionObject-oriented design is a programming paradigm that began in the late 60's as software programs became more and more complex. The idea behind the approach was to build software systems by modeling them based on the real-world objects that they were trying to represent. For example, banking systems would likely contain customer objects, account objects, etc. Today, object-oriented design has been widely adopted by businesses around the world. When done properly, the approach leads to simpler. Over the years , we've made a science out of understanding what goes into making great object-oriented design. At the heart of great design are a set of principles and patterns. Design principles form the foundation of good object-oriented design and design patterns provide general repeatable solutions for common software problems. To introduce you to the topics of principles and patterns, we've written dozens of papers. Here are just a few: The principles of Object Oriented Design and Dependency Management SRP — The Single Responsibility Principle OCP — The Open Closed Principle LSP — The Liskov Substitution Principle DIP — The Dependency Inversion Principle ISP — The Interface Segregation Principle REP — The Reuse Release Equivalency Principle CCP — The Common Closure Principle Principle CRP — The Common Reuse Principle ADP — The Acyclic Dependencies Principle SDP — The Stable Dependencies Principle SAP — The Stable Abstractions Principle Dynamic PolymorphismThe LogOn function must be changed every time a new kind of modem is added to the software. Worse, since each different type of modem depends upon the Modem::Type enumeration, each modem must be recompiled every time a new kind of modem is added. Logon, must be modified to be extended. struct Modem
{
enum Type {hayes, courrier, ernie) type;
};
struct Hayes
{
Modem::Type type;
// Hayes related stuff};
struct Courrier
{
Modem::Type type;
// Courrier related stuff};
struct Ernie
{
Modem::Type type;
// Ernie related stuff};
void LogOn(Modem& m,string& pno, string& user, string& pw)
{
if (m.type == Modem::hayes)
DialHayes((Hayes&)m, pno);
else if (m.type == Modem::courrier)
DialCourrier((Courrier&)m, pno);
else if (m.type == Modem::ernie)
DialErnie((Ernie&)m, pno)
}Of course this is not the worst attribute of this kind of design. Programs that are designed this way tend to be littered with similar if/else or switch statement. Every time anything needs to be done to the modem, a switch statement if/else chain will need to select the proper functions to use. When new modems are added, or modem policy changes, the code must be scanned for all these selection statements, and each must be appropriately modified. Worse, programmers may use local optimizations that hide the structure of the selection statements. For example, it might be that the function is exactly the same for Hayes and Courrier modems. Thus we might see code like this: if (modem.type == Modem::ernie)
SendErnie((Ernie&)modem, c);
elseSendHayes((Hayes&)modem, c); Clearly, such structures make the system much harder to maintain, and are very prone to error. that's all. |