Design Patterns: Solidify Your C # Application Architecture With Design Patterns Chinese Edition (Part 2)
Author: Samir Bajaj
Translator: glory
[Decoration: C # advanced article. The translator made a simple finishing of the C # example provided by Samir (the author provided in the translator's environment) and writes the corresponding C example, and placed in the translation. All C #, C program debugging environments in the translation are Microsoft Visual Studio.Net 7.0 Beta2]
C example:
#include "stdafx.h";
#include
#include
Using namespace std;
Class Shape
{
PUBLIC:
Virtual void Draw () {};
}
Class Line: Public Shape: PUBLIC Shape
{
Private:
Double X1, Y1, X2, Y2;
PUBLIC:
Line (Double X1, Double Y1, Double X2, Double Y2)
{
THIS-> X1 = x1;
This-> Y1 = Y1;
THIS-> X2 = x2;
This-> Y2 = Y2;
}
Void Draw ()
{
/ / Draw a line from (x1, y1) to (x2, y2)
COUT << "Drawing a line" << endl;
}
}
Class Circle: Public Shape: PUBLIC SHAPE
{
Private:
Double X, Y, R;
PUBLIC:
Circle (Double X, Double Y, Double Radius)
{
This-> x = x;
THIS-> Y = Y;
THIS-> r = r;
}
Void Draw ()
{
// With (x, y) is round, R is a radius
COUT << "Drawing a circle" << Endl;
}
}
Class Drawing: Public Shape
{
Private:
List
List
PUBLIC:
Drawing ()
{
}
~ Drawing ()
{
For (it = shapes.begin (); it! = shapes.end (); it )
{
IF (* IT)
{
Delete * it;
* it = NULL;
}
}
Shapes.clear ();
}
Void Add (Shape * S)
{
Shapes.push_back (s);
}
Void Draw ()
{
For (it = shapes.begin (); it! = shapes.end (); it )
{
(Dynamic_Cast
}
}
}
INT _Tmain (int Argc, _tchar * argv [])
{
Line * line = new line (0, 0, 10, 12);
Circle * Circle = New Circle (2, 3, 5.5);
Drawing * dwg = new drawing (); dwg-> add (new line (3, 4, 3, 5));
DWG-> Add (New Circle (5, 6, 7.7));
Shape * array [3] = {line, circle, dwg};
/ / Draw all the graphics, pay attention: Access all objects in a consistent way
For (int i = 0; i <3; i)
{
Array [I] -> DRAW ();
Delete array [i];
}
Return 0;
}
/ * The following is the program output result:
Drawing a line
Drawing a circle
Drawing a line
Drawing a circle
* /
】
State
Each developer has realized at least a limited state machine in his career career. You can't avoid them, they are everywhere, but not only limited to software development. It is also not surprising that the design and implementation of deterministic limited automobiles is also not surprising. Talking about a limited state machine, I often see the design is bad, achieving the BUG, at all, regardless of the extensibility case. The ability to add more status to a limited automatic machine is usually an incubated requirement. When you need to add more status and conversion, you often need to modify implementation. If the design is good, you can foresee and process this change. More importantly, the behavior and operational details of any state in the finite state machine should only be limited to the representation of the state. In other words, the status detail code should reside in the object that implements the state, which is easy to join the new state and easy to convert.
The method based on the table lookup is a popular design method for a limited state machine. A table maps all possible input to state transitions (that is, the limited state machine can be converted to another state). Needless to say, although this method is relatively simple, if you do not have a major modification of the existing code, it is impossible to adapt to changes. A better alternative is to use State design mode.
Assume that software is used to implement a carbonated drink vending machine, this machine only receives a coin of 5 points, 10 points and 25 points. When the coin score is accumulated or more than 25 minutes, a can of beverage is issued. Each time you put a coin in the slot, you will cause the vending to convert to a different state until the number of coins reaches the number you need, and the machine will make a can drink and reset back to the START state. Table 10 defines an abstract class State that represents the base class of all states that the vending can change.
Table 10
Abstract Class State
{
Public Virtual Void Add Nickel (VendingMachine VM) {}
Public Virtual Void AddDime (VendingMachine VM) {}
Public Virtual Void Addquarter (VendingMachine VM) {}
Protected Virtual Void ChangeState (VendingMachine VM, State S)
{
VM.ChangeState (s);
}
}
All 5 states are derived from the base class and overload the corresponding imaginary method. For example, when the vending is in the START state, it is put into a 5-point coin, and the machine changes into the FIVE state, if it is put into a 5-point coin, switch to the TEN state. This separates the conversion logic to the object of each implementation. Table 11 shows two classes of implementation.
Table 11
Class Start: State
{
Private static state statness = new start ();
Private start ()
{
}
Public Static State Instance ()
{
// Singleton logic console.writeLine ("CRedit: 0c");
Return State;
}
Public Override Void Add Nickel (VendingMachine VM)
{
ChangeState (VM, Five.instance ());
}
Public Override Void Adddime (VendingMachine VM)
{
ChangeState (VM, Ten.instance ());
}
Public Override Void Addquarter (VendingMachine VM)
{
vm.vend ();
}
}
Class Five: State
{
Private static state state = new five ();
Private file ()
{
}
Public Static State Instance ()
{
// Singleton logic
Console.writeline ("CREDIT: 5C");
Return State;
}
Public Override Void Add Nickel (VendingMachine VM)
{
ChangeState (VM, Ten.instance ());
}
Public Override Void Adddime (VendingMachine VM)
{
ChangeState (VM, Fifteen.instance ());
}
Public Override Void Addquarter (VendingMachine VM)
{
vm.vend ();
ChangeState (VM, Start.instance ()); // no change returned :-)
}
}
The vending machine does not have to care about the status conversion logic, which only use the current State instance to operate, so that it is thoroughly and the relevant status detail decouple. See Table 12.
Table 12
Class VendingMachine
{
PRIVATE STATE;
Public vendingmachine ()
{
Console.writeline ("The Vending Machine Is Now Online: Product Costs 25c");
State = start.instance ();
}
Public Void ChangeState (State To)
{
State = TO;
}
Public void vend ()
{
// send beverage
Console.WriteLine ("Dispensing Product ... Thank you!");
}
Public void add nickel ()
{
State.adDnickel (this);
}
Public void adddime ()
{
State.adddime (this);
}
Public void addquarter ()
{
State.addquarter (this);
}
}
I have explained that the State mode is better than simple, based on the implementation of the table lookup. In summary, this design pattern helps to locate status detail behavior into a class that implements specific status, so promoting software reuse and expansion. This also avoids the need to write the conditional statements in the program code, and that will make the programmer of the maintenance code, in reality, the number of programmers responsible for maintenance is far more than the initial implementator.