- 浏览: 74104 次
- 性别:
- 来自: 合肥
文章分类
最新评论
转自:http://www.codeproject.com/Articles/93369/How-I-explained-OOD-to-my-wife
Introduction
My wife Farhana wants to resume her career as a software developer (she started her career as a software developer, but couldn't proceed much because of our first child's birth), and these days, I am trying to help her learn Object Oriented Designs as I've got some experience in software design and development.
Since my early days in software development, I have always observed that no matter how hard a technical issue seems, it always becomes easier if explained from a real life perspective and discussed in a conversational manner. As we had some fruitful conversations on Object Oriented Designs, I thought I could share it because someone might find it an interesting way of learning OOD.
Following is how our OOD conversation took place:
Topic: Introducing OOD
Shubho: Darling, let's start learning Object Oriented Designs. You know Object Oriented Principles, right?
Farhana: You mean, Encapsulation, Inheritance, and Polymorphism, right? Yes, I know the principles.
Shubho: OK, I hope you already know how to use classes and objects. Let us learn Object Oriented Designs today.
Farhana: Hold on a second. Isn't Object Oriented Principles enough to do Object Oriented programming? I mean, I can define classes and encapsulate properties and methods. I can also define a class hierarchy based upon their relationship. So, what's left?
Shubho: Good question. Object Oriented Principles and Object Oriented Design are actually two different things. Let me give you a real life example to help you understand.
When you were child you learned alphabets first, right?
Farhana: Yes.
Shubho: OK. You also learned words and how to assemble the alphabets to make those meaningful words. Along with that, you learned some basic grammar to assemble the words into sentences. For example, you had to maintain tenses, and you had to use prepositions, conjunctions, and others properly to create grammatically correct sentences. Say, a sentence like the following:
"I" (pronoun) "want" (Verb) "to" (Preposition) "learn" (Verb) "OOD" (Noun)
You see, you are assembling the words in some order, and you are also choosing the correct words to end up with a sentence that has some meaning.
Farhana: OK, so, what does this mean?
Shubho: This is analogous to Object Oriented Principles. OOP says about the basic principles and the core ideas to do Object Oriented programming. Here, OOP can be compared to the basic English grammar, where the basic grammar teaches you how to construct a meaningful and correct sentence using words, and OOP teaches you to construct classes, encapsulate properties and methods inside them, and also develop a hierarchy between them and use them in your code.
Farhana: Hm..I got the point. So, where does OOD fit here?
Shubho: You'll get your answer soon. Now, suppose you need to write articles and essays on some topics. You may also wish to write books on different subjects that you have expertise on. Knowing how to construct sentences is not enough to write good essays/articles or books, right? You need to write a lot, and need to learn to explain things in a good way so that readers can easily understand what you are trying to say.
Farhana: Seems interesting... carry on.
Shubho: Now, if you want to write a book on a particular subject (say, Learning Object Oriented Design), you got to know how to divide the subject into smaller topics. You also need to write chapters on those topics, and you need to write prefaces, introductions, explanations, examples, and many other paragraphs in the chapters. You need to design the overall book and learn some best practices of writing techniques so that the reader can easily understand what you are trying to explain. This is about the bigger picture.
In software development, OOD addresses the bigger picture. You need to design your software in a way that your classes and code are modularized, re-usable, and flexible, and there are some good guidelines to do that so that you don't have to re-invent the wheel. There are some design principles that you can apply to design your classes and objects. Makes sense?
Farhana: Hmm.. got the initial idea, but need to learn more.
Shubho: Don't worry, you will learn soon. Just let our discussion going.
Topic: Why OOD?
Shubho: This is a very important question. Why should we care about Object Oriented Design when we can create some classes quickly and finish development and deliver? Isn't that enough?
Farhana: Yes, I didn't know about OOD earlier, and still I was able to develop and deliver projects. So, what is the big deal?
Shubho: OK, let me get a classic quote for you:
"Walking on water and developing software from a specification are easy if both are frozen."
Farhana: You mean software development specifications keep changing constantly?
Shubho: Exactly! The universal truth of software is "your software is bound to change". Why?
Because, your software solves real life business problems and real life business processes evolve and change - always.
Your software does what it is supposed to do today and does it good enough. But, is your software smart enough to support "changes"? If not, you don't have a smartly designed software.
Farhana: OK, so, please explain "smartly designed software" sir!
Shubho: "A smartly designed software can adjust changes easily; it can be extended, and it is re-usable."
And, applying a good "Object Oriented Design" is the key to achieve such a smart design. Now, when can you claim that you have applied good OOD in your code?
Farhana: That's my question too.
Shubho: You are doing Object Oriented Design if your code is:
- Of course, object oriented.
- Re-usable.
- Can be changed with minimal effort.
- Can be extended without changing existing code.
Farhana: And..?
Shubho: We are not alone. Many people have already given lots of thoughts and put a lot of effort on this issue, and they've tried to achieve good Object Oriented Design and identify some basic principles for doing Object Oriented Design (some basic inspirations which you can use to lay out your object oriented design). They also have identified some common design patterns that are applicable to common scenarios (based on the basic principles).
Farhana: Can you name some?
Shubho: Sure. There are many design principles out there, but at the basic level, there are five principles which are abbreviated as the SOLID principles (thanks to Uncle Bob, the great OOD mentor).
S = Single Responsibility Principle O = Opened Closed Principle L = Liscov Substitution Principle I = Interface Segregation Principle D = Dependency Inversion Principle
In the following discussion, we will try to understand each of these in detail.
Topic: Single Responsibility Principle
Shubho: Let me show you the poster first. We should thank the person who made the posters, these are really interesting.
It says, "just because you can implement all the features in a single device, you shouldn't". Why? Because it adds a lot of manageability problems for you in the long run.
Let me tell you the principle in Object Oriented terms.
"There should never be more than one reason for a class to change."
Or, differently said: "A class should have one and only one responsibility".
Farhana: Can you please explain?
Shubho: Sure, this principle says that if you have a class that has more than one reason to change (or has more than one overall responsibility), you need to split the class into multiple classes based upon their responsibility.
Farhana: Hmm... does that mean that I can't have multiple methods in a single class?
Shubho: Not at all. Rather, you surely can have multiple methods in a single class. The issue is, they have to meet a single purpose. Now, why is splitting important?
It's important because:
- Each responsibility is an axis of change.
- Code becomes coupled if classes have more than one responsibility.
Farhana: Could you please give me an example?
Shubho: Sure, take a look at the following class hierarchy. Actually, this example is taken from Uncle Bob, so thanks to him again.
Here, the Rectangle
class does the following:
- It calculates the value of the rectangular area.
- It renders the rectangle in the UI.
And, two applications are using this Rectangle
class:
- A computational geometry application uses this class to calculate the area
- A graphical application uses this class to draw a rectangle in the UI
This is violating the SRP (Single Responsibility Principle)!
Farhana: How?
Shubho: You see, the Rectangle
class is actually performing two different things. It is calculating the area in one method, and it is returning a GUI representation of the rectangle in another method. This leads to some interesting problems:
- We must include the GUI in the computational geometry application. While deploying the geometry application, we must include the GUI library.
- A change to the
Rectangle
class for the graphical application may lead to a change, build, and test for the computational geometry application, and vice-versa.
Farhana: It's getting interesting. So I guess we should break up the class based on its responsibilities, right?
Shubho: Exactly. Can you predict what we should do?
Farhana: Sure, let me try. Following is what we might need to do:
Separate the responsibilities into two different classes, such as:
-
Rectangle
: This class should define thearea()
method. -
RectangleUI
: This class should inherit theRectangle
class and define theDraw()
method.
Shubho: Perfect. In this case, the Rectangle
class will be used by the computational geometry application, and theRectangleUI
class will be used by the graphical application. We could even separate the classes into two separate DLLs, and that will allow us not to touch the other in case a change is needed to be implemented in one.
Farhana: Thanks, I think I understand SRP. One thing, SRP seems to be an idea of breaking things into molecular parts so that it becomes reusable and can be managed centrally. So, shouldn't we apply SRP in the method level as well? I mean, we might have written methods that have many lines of code for doing multiple things. These methods might be violating SRP, right?
Shubho: You got it right. You should break down your methods so that each method does a particular work. That will allow you to re-use methods, and in case a change is required, you are able to do the change by modifying minimal amount of code.
Topic: Open-Closed Principle
Shubho: Here goes the poster for the Open-Closed Principle:
Figure: Open Closed Principle poster
If I need to explain it in design oriented terms, it would be as follows:
"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."
At the most basic level, that means, you should be able to extend a class's behavior without modifying it. It's just like I should be able to put on a dress without doing any change to my body, ha ha.
Farhana: Interesting. You can change your look by putting any dress you want, and you don't have to change your body for that. So you are open for extension, right?
Shubho: Yes. In OOD, open for extensions means that the behavior of the module/class can be extended and we can make the module behave in new and different ways as the requirements change, or to meet the needs of new applications.
Farhana: And your body is closed for modification. I like this example. So, the source code for a core class or module should not be modified when it needs an extension. Can you explain with some examples?
Shubho: Sure, take a look at the following example. This doesn't support the "Open-Closed" principle:
You see, the Client and Server classes are both concrete. So, if for any reason, the server implementation is changed, the client also needs a change.
Farhana: Makes sense. If a browser is implemented as tightly coupled to a specific server (such as IIS), then if the server is replaced for some reason with another one (say, Apache) the browser also needs to be changed or replaced. That would be really horrible!
Shubho: Correct. So following would be the correct design:
In this example, there is an Abstract Server class added, and the client holds a reference to the abstract class, and the Concrete Server class implements the Abstract Server class. So, if for any reason the Server implementation is changed, the Client is not likely to require any change.
The Abstract Server class here is closed for modification, and the concrete class implementations here are open for extension.
Farhana: As I understand, abstraction is the key, right?
Shubho: Yes, basically, you abstract the things that are the core concepts of your system, and if you do the abstraction well, most likely, it would require no change when the functionality is to be extended (such as the server is an abstract concept). And, you define the abstract things in the implementations (say, IISServer implements the Server) and code against abstractions (Server) as much as possible. This would allow you to extend the abstract thing and define a new implementation (say, ApacheServer) without doing any change in the client code.
Topic: Liskov's Substitution Principle
Shubho: The name "Liskov's Substitution Principle" sounds very heavy, but the idea is pretty basic. Take a look at this interesting poster:
The principle says:
"Subtypes must be substitutable for their base types."
Or, if said differently:
"Functions that use references to base classes must be able to use objects of derived classes without knowing it."
Farhana: Sorry, sounds confusing to me. I thought this is the basic rule of OOP. This is polymorphism, right? Why was an Object Oriented Principle required on this issue?
Shubho: Good question. Here is your answer:
In basic Object Oriented Principles, "Inheritance" is usually described as an "is a" relationship. If a "Developer" is a "SoftwareProfessional", then the "Developer" class should inherit the "SoftwareProfessional" class. Such "Is a" relationships are very important in class designs, but it's easy to get carried away and end up in a wrong design with a bad inheritance.
The "Liskov's Substitution Principle" is just a way of ensuring that inheritance is used correctly.
Farhana: I see. Interesting.
Shubho: Yes darling, indeed. Let's take a look at an example:
Here, the KingFisher
class extends the Bird
base class and hence inherits the Fly()
method, which is pretty good.
Now take a look at the following example:
Ostrich is a Bird (definitely it is!) and hence it inherits the Bird class. Now, can it fly? No! Here, the design violates the LSP.
So, even if in real world this seems natural, in the class design, Ostrich should not inherit the Bird class, and there should be a separate class for birds that can't really fly and Ostrich should inherit that.
Farhana: OK, understood. So, let me try to point out why the LSP is so important:
- If LSP is not maintained, class hierarchies would be a mess, and if a subclass instance was passed as parameter to methods, strange behavior might occur.
- If LSP is not maintained, unit tests for the base classes would never succeed for the subclass.
Am I right?
Shubho: You are absolutely right. You can design objects and apply LSP as a verification tool to test the hierarchy whether inheritance is properly done.
Topic: The Interface Segregation Principle
Shubho: Today, we will learn the "Interface Segregation Principle". Here is the poster:
Farhana: What does it mean?
Shubho: It means the following:
"Clients should not be forced to depend upon interfaces that they do not use."
Farhana: Explain please.
Shubho: Sure, here is your explanation:
Suppose you want to purchase a television and you have two to choose from. One has many switches and buttons, and most of those seem confusing and doesn't seem necessary to you. Another has a few switches and buttons, which seems familiar and logical to you. Given that both televisions offer roughly the same functionality, which one would you choose?
Farhana: Obviously the second one with the fewer switches and buttons.
Shubho: Yes, but why?
Farhana: Because I don't need the switches and buttons that seem confusing and unnecessary to me.
Shubho: Correct. Similarly, suppose you have some classes and you expose the functionality of the classes using interfaces so that the outside world can know the available functionality of the classes and the client code can be done against interfaces. Now, if the interfaces are too big and have too many exposed methods, it would seem confusing to the outside world. Also, interfaces with too many methods are less re-usable, and such "fat interfaces" with additional useless methods lead to increased coupling between classes.
This also leads to another problem. If a class wants to implement the interface, it has to implement all of the methods, some of which may not be needed by that class at all. So, doing this also introduces unnecessary complexity, and reduces maintainability or robustness in the system.
The Interface Segregation principle ensures that Interfaces are developed so that each of them have their own responsibility and thus they are specific, easily understandable, and re-usable.
Farhana: I see. You mean interfaces should contain only the necessary methods and not anything else?
Shubho: Exactly. Let's see an example.
The following interface is a "Fat interface" which violates the Interface Segregation principle:
Note that the IBird
interface has many bird behaviours defined along with the Fly()
behaviour. Now, if a Bird class (say, Ostrich) implements this interface, it has to implement the Fly()
behaviour unnecessarily (Ostrich doesn't fly).
Farhana: That's correct. So, this interface must be split?
Shubho: Yes. The "Fat Interface" should be broken down into two different interfaces, IBird
and IFlyingBird
, where the IFlyingBird
inherits IBird
.
If there is a bird that can't fly (say, Ostrich), it would implement the IBird
interface. And if there is a bird that can fly (say, KingFisher), it would implement the IFlyingBird
interface.
Farhana: So, if I go back to the example with the television with many switches and buttons, the manufacturer of that television must have a blueprint of that television where the switches and buttons are included in the plan. Whenever they want to create a new model of the television, if they need to re-use this blueprint, they would need to create as many switches and buttons as included in the plan. That wouldn't allow them to re-use the plan, right?
Shubho: Right.
Farhana: And, if they really want to re-use their plans, they should divide their television's blueprint into smaller pieces so that they can re-use the plan whenever any new kind of television is to be created.
Shubho: You got the idea.
Topic: The Dependency Inversion Principle
Shubho: This is the last principle among the SOLID principles. Here is the poster:
It says..
"High level modules should not depend upon low level modules. Rather, both should depend upon abstractions."
Shubho: Let's consider a real world example to understand it. Your car is composed of lots of objects like the engine, the wheels, the air conditioner, and other things, right?
Farhana: Yes, of course.
Shubho: OK, none of these things are rigidly built within a single unit; rather, each of these are "pluggable" so that when the engine or the wheel has problem, you can repair it (without repairing the other things) and you can even replace it.
While replacement, you just have to ensure that the engine/wheel conforms to the car's design (say, the car would accept any 1500 CC engine and will run on any 18 inch wheel).
Also, the car might allow you to put a 2000 CC engine in place of the 1500 CC, given the fact that the manufacturer (say, Toyota) is the same.
Now, what if the different parts of your car were not built in such a "pluggable nature"?
Farhana: That would be horrible! Because, in that case, if your car's engine is out of order, you will have to fix the whole car or purchase a new one!
Shubho: Yes. Now, how can the "pluggable nature" be achieved?
Farhana: "Abstraction" is the key, right?
Shubho: Yes. In real world, Car is the higher level module/entity, and it depends on the lower level modules/entities like the Engines or Wheels.
Rather than directly depending on the Engines or Wheels, the car depends on the abstraction of some specification of Engine or Wheels so that if any the Engine or Wheel conforms to the abstraction, these could be assembled with the car and the car would run.
Let's take a look at the following class diagram:
Shubho: In the above Car
class, notice that there are two properties, and both of these are of abstract type (Interface) rather than concrete type.
The Engine and Wheels are pluggable because the car would accept any object implementing the declared interfaces, and that will not require any change in the Car
class.
Farhana: So, if Dependency Inversion is not implemented in the code, we run the risk of:
- Damaging the higher level code that uses the lower level classes.
- Requiring too much time and effort to change the higher level code when a change occurs in the lower level classes.
- Producing less-reusable code.
Shubho: You got it perfect darling!
Summary
Shubho: There are many other Object Oriented principles other than the SOLID principles. Some are:
- "Composition over Inheritance": This says about favoring composition over inheritance.
- "Principle of least knowledge": This says that "the less your class knows, the better".
- "The Common Closure principle" : This says that "related classes should be packaged together".
- "The Stable Abstractions principle": This says that "the more stable a class is, the more it must consist of abstract classes."
Farhana: Shouldn't I learn those principles too?
Shubho: Yes, of course. You have the whole world wide web to learn from. Just Google on those principles and try to understand. And of course, don't hesitate me to ask me if you need help.
Farhana: I've heard there are many Design Patterns built upon those design principles.
Shubho: You are right. Design Patterns are nothing but some commonly suggested design suggestions in commonly recurring situations. These are mainly inspired by the Object Oriented Design principles. You can think of Design Patterns as "Frameworks" and OOD principles as "Specifications".
Farhana: So, am I going to learn Design Patterns next?
Shubho: Yes darling.
Farhana: That would be exiting, right?
Shubho: Yes, that would be really exiting.
Introduction
Me and my wife had some interesting conversations on Object Oriented Design principles. After publishing the conversation on CodeProject, I got some good responses from the community and that really inspired me. So, I am happy to share our next conversation that took place on Object Oriented Design Patterns. Here it is.
What is a Design Pattern?
Shubho: I guess you already have some basic idea about Object Oriented Design principles. We had a nice talk on the OOD principles (SOLID principles), and I hope you didn't mind that I published our conversation in a CodeProject article. You can find it here: How I explained OOD to my wife.
Design Patterns are nothing but applications of those principles in some specific and common situations, and standardizing some of those. Let's try to understand what Design Patterns are by using some examples.
Farhana: Sure, I love examples.
Shubho: Let's talk about our car. It's an object, though a complex one, which consists of thousands of other objects such as the engine, wheels, steering, seats, body, and thousands of different parts and machinery.
While building this car, the manufacturer gathered and assembled all the different smaller parts that are subsystems of the car. These different smaller parts are also some complex objects, and some other manufacturers had to build and assemble those too. But, while building the car, the car company doesn't really bother too much about how those objects were built and assembled (well, as long as they are sure about the quality of these smaller objects/equipments). Rather, the car manufacturer cares about how to assemble those different objects into different combinations and produce different models of cars.
Farhana: The car manufacturer company must have some designs or blue prints for each different model of car which they follow, right?
Shubho: Definitely, and, these designs are well-thought designs, and they've put a good amount of time and effort to sketch those designs. Once the designs are finalized, producing a car is just a matter of following the designs.
Farhana: Hm.. it's good to have some good designs upfront and following those allows to produce different products in a quick amount of time, and each time the manufacturer has to build a product for a specific model, they don't have to develop a design from scratch or re-invent the wheel, they just follow the designs.
Shubho: You got the point. Now, we are software manufacturers and we build different kinds of software programs with different components or functionality based upon the requirements. While building such different software systems, we often have to develop code for some situations that are common in many different software systems, right?
Farhana: Yes. And often, we face common design problems while developing different software applications.
Shubho: We try to develop our software applications in an Object Oriented manner and try to apply OOD principles for achieving code that is manageable, reusable, and expandable. Wouldn't it be nice whenever we see such design problems, we have a pool of some carefully made and well tested designs of objects for solving those?
Farhana: Yes, that would save us time and would also allow us to build better software systems and manage them later.
Shubho: Perfect. The good news is, you don't have to really develop that pool of object designs from scratch. People already have gone through similar design problems for years, and they already have identified some good design solutions which have been standardized already. We call these Design Patterns.
We must thank the Gang of Four (GoF) for identifying the 23 basic Design Patterns in their book Design Patterns: Elements of Reusable Object-Oriented Software. In case you are wondering who formed this famous gang, they are Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. There are many Object Oriented Design Patterns, but these 23 patterns are generally considered the foundation for all other Design Patterns.
Farhana: Can I create a new pattern? Is that possible?
Shubho: Yes darling, why not? Design Patterns are not something invented or newly created by scientists. They are just discovered. That means, for each kind of common problem scenario, there must be some good design solutions there. If we are able to identify an object oriented design that could solve a new design related problem, that would be a new Design Pattern defined by us. Who knows? If we discover some a Design Pattern, someday people may call us Gang of Two.. Ha ha.
Fahana: :)
How will we learn Design Patterns?
Shubho: As I have always believed, examples are the greatest way of learning. In our learning approach, we won't discuss the theories first and implement later. I think this is a BAD approach. Design Patterns were not invented based on theories. Rather, the problem situations occurred first and based upon the requirement and context, some design solutions were evolved, and later some of them were standardized as patterns. So, for each design pattern we discuss, we will try to understand and analyze some real life example problems, and then we will try to formulate a design in a step by step process and end up with a design that will match with some patterns; Design Patterns were discovered in this same process. What do you think?
Farhana: I think this approach makes more sense to me. If I can end up with Design Patterns by analyzing problems and formulating solutions, I won't have to memorize design diagrams and definitions. Please proceed using your approach.
A basic design problem and its solution
Shubho: Let's consider the following scenario:
Our room has some electric equipments (lights, fans etc). The equipments are arranged in a way where they could be controlled by switches. At any time, you can replace or troubleshoot an electrical equipment without touching the other things. For example, you can replace a light with another without replacing or changing the switch. Also, you can replace a switch or troubleshoot it without touching or changing the corresponding light or fan; you can even connect the light with the fan's switch and connect the fan with the light's switch, without touching the switches.
Farhana: Yes, but that's natural, right?
Shubho: Yes, that's very natural, and that's how the arrangement should be. When different things are connected together, they should be connected in a way where change or replacement of one system doesn't affect another, or even if there is any effect, it stays minimal. This allows you to manage your system easily and at low cost. Just imagine if changing the light in your room requires you to change the switch also. Would you care to purchase and set up such a system in your house?
Farhana: Definitely no.
Shubho: Now, let's think how the lights or fans are connected with the switches so that changing one doesn't have any impact on the other. What do you think?
Farhana: The wire, of course!
Shubho: Perfect. It's the wire and the electrical arrangement that connect the lights/fans with the switches. We can generalize it as a bridge between the different systems that can get connected through it. The basic idea is, things shouldn't be directly connected with one another. Rather, they should be connected though some bridges or interfaces. That's what we call "loose coupling" in software world.
Farhana: I see. I got the idea.
Shubho: Now, let's try to understand some key issues in the light/fan and switch analogy, and try to understand how they are designed and connected.
Farhana: OK, let me try.
We have switches in our example. There may be some specific kinds of switches like normal switches, fancy ones, but, in general, they are switches. And, each switch can be turned on and off.
So, we will have a base Switch
class as follows:
public class Switch { public void On() { //Switch has an on button } public void Off() { //Switch has an off button } }
And, as we may have some specific kinds of switches, for example a fancy switch, a normal switch etc., we will also have FancySwitch
and NormalSwitch
classes extending the Switch
class:
public class NormalSwitch : Switch { } public class FancySwitch : Switch { }
These two specific switch classes may have their own specific features and behaviours, but for now, let's keep them simple.
Shubho: Cool. Now, what about fan and light?
Farhana: Let me try. I learned from the Open Closed principles from Object Oriented Design principles that we should try to do abstractions whenever possible, right?
Shubho: Right.
Farhana: Unlike switches, fan and light are two different things. For switches, we were able to use a base Switch
class, but as fan and light are two different things, instead of defining a base class, an interface might be more appropriate. In general, they are all electrical equipments. So, we can define an interface, say,IElectricalEquipment
, for abstracting fans and lights, right?
Shubho: Right.
Farhana: OK, each electrical equipment has some common functionality. They could all be turned on or off. So the interface may be as follows:
public interface IElectricalEquipment { void PowerOn(); //Each electrical equipment can be turned on void PowerOff(); //Each electrical equipment can be turned off }
Shubho: Great. You are getting good at abstracting things. Now, we need a bridge. In real world, the wires are the bridges. But, in our object design, a switch knows how to turn on or off an electrical equipment, and the electrical equipment somehow needs to be connected with the switches, As we don't have any wire here, the only way to let the electrical equipment be connected with the switch is encapsulation.
Farhana: Yes, but switches don't know the fans or lights directly. A switch actually knows about an electrical equipment IElectricalEquipment
that it can turn on or off. So, that means, an ISwitch
should have anIElectricalEquipment
instance, right?
Shubho: Right. Here, the encapsulated instance, which is an abstraction of fan or light (IElectricalEquipment
) is the bridge. So, let's modify the Switch
class to encapsulate an electrical equipment:
public class Switch { public IElectricalEquipment equipment { get; set; } public void On() { //Switch has an on button } public void Off() { //Switch has an off button } }
Farhana: Understood. Let me try to define the actual electrical equipments, the fan and the light. As I see, these are electrical equipments in general, so these would simply implement the IElectricalEquipment
interface.
Following is the Fan
class:
public class Fan : IElectricalEquipment { public void PowerOn() { Console.WriteLine("Fan is on"); } public void PowerOff() { Console.WriteLine("Fan is off"); } }
And, the Fan
class would be as follows:
public class Light : IElectricalEquipment { public void PowerOn() { Console.WriteLine("Light is on"); } public void PowerOff() { Console.WriteLine("Light is off"); } }
Shubho: Great. Now, let's make switches work. The switches should have the ability inside them to turn on and turn off the electrical equipment (it is connected to) when the switch is turned on and off.
These are the key issues:
- When the On button is pressed on the switch, the electrical equipment connected to it should be turned on.
- When the Off button is pressed on the switch, the electrical equipment connected to it should be turned off.
Basically, following is what we want to achieve:
static void Main(string[] args) { //We have some electrical equipments, say Fan, Light etc. //So, lets create them first. IElectricalEquipment fan = new Fan(); IElectricalEquipment light = new Light(); //We also have some switches. Lets create them too. Switch fancySwitch = new FancySwitch(); Switch normalSwitch = new NormalSwitch(); //Lets connect the Fan to the fancy switch fancySwitch.equipment = fan; //As the switch now has an equipment (Fan), //so switching on or off should //turn on or off the electrical equipment fancySwitch.On(); //It should turn on the Fan. //so, inside the On() method of Switch, //we must turn on the electrical equipment. //It should turn off the Fan. So, inside the On() method of fancySwitch.Off(); //Switch, we must turn off the electrical equipment //Now, lets plug the light to the fancy switch fancySwitch.equipment = light; fancySwitch.On(); //It should turn on the Light now fancySwitch.Off(); //It should be turn off the Light now }
Farhana: I got it. So, the On()
method of the actual switches should internally call the TurnOn()
method of the electrical equipment, and the Off()
should call the TurnOff()
method on the equipment. So, the Switch
class should be as follows:
public class Switch { public void On() { Console.WriteLine("Switch on the equipment"); equipment.PowerOn(); } public void Off() { Console.WriteLine("Switch off the equipment"); equipment.PowerOff(); } }
Shubho: Great work. Now, this certainly allows you to plug a fan from one switch to another. But you see, the opposite should also work. That means, you can change the switch of a fan or light without touching the fan or light. For example, you can easily change the switch of the light from FancySwitch
to NormalSwitch
as follows:
normalSwitch .equipment = light; normalSwitch.On(); //It should turn on the Light now normalSwitch.Off(); //It should be turn off the Light now
So, you see, you can vary both the switches and the electrical equipments without any effect on the other, and connecting an abstraction of the electrical equipment with a switch (via encapsulation) is letting you do that. This design looks elegant and good. The Gang of Four has named this a pattern: The Bridge Pattern.
Farhana: Cool. I think I've understood the idea. Basically, two systems shouldn't be connected or dependent on another directly. Rather, they should be connected or dependent via abstraction (as the Dependency Inversion principle and the Open-Closed principle say) so that they are loosely coupled, and thus we are able to change our implementation when required without much effect on the other part of the system.
Shubho: You got it perfect darling. Let's see how the Bridge Pattern is defined:
"Decouple an abstraction from its implementation so that the two can vary independently"
You will see that our design perfectly matches the definition. If you have a class designer (in Visual Studio, you can do that, and other modern IDEs should also support this feature), you will see that you have a class diagram similar to the following:
Here, Abstraction is the base Switch
class. RefinedAbstraction is the specific switch classes (FancySwitch
,NormalSwitch
etc.). Implementor is the IElectricalEquipment
interface. ConcreteImplementorA andConcreteImplementorB are the Fan
and Light
classes.
Farhana: Let me ask you a question, just curious. There are many other patterns as you said, why did you start with the Bridge pattern? Any important reason?
Shubho: A very good question. Yes, I started with the Bridge pattern and not any other pattern (unlike many others) because of a reason. I believe the Bridge pattern is the base of all Object Oriented Design Patterns. You see:
- It teaches how to think abstract, which is the key concept of all Object Oriented Design Patterns.
- It implements the basic OOD principles.
- It is easy to understand.
- If this pattern is understood correctly, learning other Design Patterns becomes easy.
Farhana: Do you think I have understood it correctly?
Shubho: I think you have understood it perfectly darling.
Farhana: So, what's next?
Shubho: By understanding the Bridge pattern, we have just started to understand the concepts of Design Patterns. In our next conversation, we would learn other Design Patterns, and I hope you won't get bored learning them.
Farhana: I won't. Believe me.
发表评论
-
软件设计简单步骤
2012-03-09 10:32 1142参考:http://ticktick.blog.51c ... -
JAVA 实现HTTP下载
2012-03-06 15:24 1063public static void getRemo ... -
JAVA 常用算法 复杂度对比
2012-02-09 17:12 1007常用排序方法的时间复杂度 -
时间复杂度和空间复杂度
2012-02-09 16:42 1111算法复杂度 算法复杂度分为时间复杂度和空间复杂度。其作用: ... -
JAVA 常用数据结构 复杂度对比
2012-02-09 16:20 2057JAVA 常用数据结构 各种操作的时间复杂度对比 ... -
GIT 使用经验(4) ---版本的还原
2012-02-08 11:12 13546首先,在确认需要进行版本还原以后, 打开GIT BASH ... -
JAVA 简单排序总结
2012-02-08 10:54 795插入排序 算法描述 一般来说,插入排序都采用i ...
相关推荐
How to be a Programmer: Community Version Robert L. Read with Community Copyright 2002, 2003, 2016 Robert L. Read Licensed under Creative Commons Attribution-ShareAlike 4.0 International License. ...
If you have ever bought any programming books, you might have noticed that there are two types of them: books that are too short to understand the topic and books that are too long making it ...
ll learn Game development with Unity and iPhone OpenGL Unit testing and iPhone-specific testing tools How to approach and solve complex app development roadblocks The best code fully explained and ...
Drupal 8 Explained: Your Step-by-Step Guide to Drupal 8 (The Explained Series) by Stephen Burge English | 3 Apr. 2017 | ASIN: B06Y1VN2D7 | 283 Pages | AZW3 | 13.66 MB We're delighted to present the ...
Exactly how permissions work and how to decipher the most cryptic Linux permissions with ease. How to use the nano, vi, and emacs editors. Two methods to search for files and directories. How to ...
Chapter 6, Touch Patterns, teaches you how to work with the Multi-Touch interface, including design patterns for standard and custom gestures. Chapter 7, Interaction Patterns and Controls, covers ...
《MDA Explained: The Practice and Promise of the Model Driven Architecture》是一本深入探讨模型驱动架构(Model Driven Architecture,简称MDA)及其应用的书籍。本书由Anneke Kleppe、Jos Warmer和Wim Bast三...
When it comes to relational databases, I can’t help thinking that something is missing. They’re used everywhere. There are many different databases: from the small and useful SQLite to the powerful ...
I've explained how to build them in a straightforward way so that everything you need to know is in there, including what materials you need for the projects and where to get them. I've also tried to...
I explained how package management was nice, but enforcing file system isolation as a default solved several management problems. I rattled on about resource efficiency and provisioning latency. I ...
In this book, you’ll see the code and learn how to use it to make your own cool applications. You’ll learn everything from importing 3D art assets into your iPhone game to using Cocos2d for iPhone ...
机器学习与深度学习对于初学者来说可能看起来晦涩难懂,但本书试图以一种老奶奶也能理解的方式,从视觉和解释上为初学者揭开深度学习神经网络的神秘面纱。以下将详细阐述书中提到的关键知识点,包括机器学习、神经...
I have been asked what is essentially the same question many times and in many places ranging from email discussions to audience questions at academic conferences to business tutorial presentations to...
Neural Networks & Deep Learning Deep Learning explained to your granny – A visual introduction for beginners who want to make their own Deep Learning Neural Network By Pat Nakamoto 神经网络与深度学习...
Bob大叔(Robert C. Martin)关于C++开发思想的大作,看他的书上提及过,好多C++高手也提及过,... The principles of OOD explained, one by one, and then demonstrated with numerous examples and case studies.