PHP object-oriented visitor mode + combination mode, object-oriented visitor Mode
Because the original text continues the code example of the combination mode to show the visitor mode, we will merge the code here to review it. However, we mainly focus on the visitor mode. As the name suggests, this model has a visitor class (just like the examiner in the recent hot play "people's name", who ran to the home of the corrupt official to investigate and obtain evidence, and then convicted after the investigation ), when the visitor class calls the visitor class, it will pass itself to it for use. View the Code directly:
// Base class of the visitor
Abstract class Unit {
Abstract function bombardStrength (); // gets the Unit's attack power
// This method will call the visitor class and pass itself to it
Function accept (ArmyVisitor $ visitor ){
$ Method = "visit". get_class ($ this );
$ Visitor-> $ method ($ this); // call the method of the visitor class. "visit". get_class ($ this) is used to constitute the name of the method.
}
// Set a depth according to the original article, although this method will be called later, it is not important to understand this mode. (In the original sample code, there are often some codes that do not have much to do with understanding the mode principle)
Protected function setDepth ($ depth ){
$ This-> depth = $ depth;
}
Function getDepth (){
Return $ this-> depth;
}
}
// Archer
Class Archer extends Unit {
Function bombardStrength (){
Return 4;
}
}
// Laser gun
Class LaserCannonUnit extends Unit {
Function bombardStrength (){
Return 44;
}
}
// Cavalry
Class Cavalry extends Unit {
Function bombardStrength (){
Return 2; // is the attacking power of the cavalry less powerful than that of the archer?
}
}
// Used to combine instances that inherit the unit class and let the Army and TroopCarrier classes inherit the removeUnit and addUnit methods, the base class is not put because the above three classes are already the smallest units, and the removeUnit and addUnit methods are not useful to them.
Abstract class CompositeUnit extends Unit {
Private $ units = array (); // stores any instances that inherit the unit class
Function getComposite () {// This method is mainly used to determine whether the current instance is a CompositeUnit class
Return $ this;
}
Protected function units (){
Return $ this-> units;
}
Function removeUnit (Unit $ unit) {// delete a military Unit
$ This-> units = array_udiff (
$ This-> units, array ($ unit ),
Function ($ a, $ B) {return ($ a ===$ B )? 0: 1 ;}
);
}
Function addUnit (Unit $ unit) {// Add a military Unit
If (in_array ($ unit, $ this-> units, true )){
Return;
}
$ Unit-> setDepth ($ this-> depth + 1 );
$ This-> units [] = $ unit;
}
Function bombardStrength (){
$ Ret = 0;
Foreach ($ this-> units as $ unit ){
$ Ret + = $ unit-> bombardStrength ();
}
Return $ ret;
}
Function accept (Armyvisitor $ visitor) {// call the visitor
Parent: accept ($ visitor); // call the accept method of the base class. In the first client code entry, an overall information of the military group will be saved.
Foreach ($ this-> units as $ thisunit) {// call the accept method of a military unit. The information of each military unit is saved in the first client code entry.
$ Thisunit-> accept ($ visitor );
}
}
}
// Army
Class Army extends CompositeUnit {
}
// Fleet
Class TroopCarrier extends CompositeUnit {
}
// Visitor class
Abstract class ArmyVisitor {
Abstract function visit (Unit $ node); // business logic to be executed by visitors
Function visitArcher (Archer $ node) {// In fact, I think this abstract class has an abstract method visit (). In the original article, the following methods are provided to call visit in a circle.
//......
$ This-> visit ($ node );
}
Function visitCavalry (Cavalry $ node ){
//.......
$ This-> visit ($ node );
}
Function visitLaserCannonUnit (LaserCannonUnit $ node ){
//......
$ This-> visit ($ node );
}
Function visitTroopCarrierUnit (Cavalry $ node ){
//......
$ This-> visit ($ node );
}
Function visitArmy (Cavalry $ node ){
//......
$ This-> visit ($ node );
}
}
// This visitor class is mainly used to obtain and save the information of the object to be visited.
Class TextDumpArmyVisitor extends ArmyVisitor {
Private $ text = "";
Function visit (Unit $ node ){
$ Ret = "";
$ Pad = 4 * $ node-> getDpth ();
$ Ret. = sprintf ("% {$ pad} s ","");
$ Ret. = get_class ($ node ).":";
$ Ret. = "bombard:". $ node-> bombardStrength (). "\ n ";
$ This-> text. = $ ret;
}
Function getText (){
Return $ this-> text;
}
}
// Visitor class used to tax each object, which will be called in client code 2
Class TaxCollectionVisitor extends ArmyVisitor {
Private $ due = 0;
Private $ report = "";
Function visit (Unit $ node ){
$ This-> levy ($ node, 1 );
}
Function visitArcher (Archer $ node) {// describes the parent class method and applies different taxes to different units.
$ This-> levy ($ node, 2 );
}
Function visitCavalry (Cavalry $ node ){
$ This-> levy ($ node, 3 );
}
Function visitTroopCarrierUnit (TroopCarrierUnit $ node ){
$ This-> levy ($ node, 5 );
}
Private function levy (Unit $ unit, $ amount) {// main business logic
$ This-> report. = "Tax levied for". get_class ($ unit );
$ This-> report. = ": $ amount \ n ";
$ This-> due + = $ amount;
}
Function getReport (){
Return $ this-> report;
}
Function getTax (){
Return $ this-> due;
}
}
// Client code 1 (obtain and output some information about each object)
Class UnitScript {
Static function joinExisting (Unit $ newUnit, Unit $ occupyingUnit ){
$ Comp;
If (! Is_null ($ com = $ occupyingUnit-> getComposite ())){
$ Comp-> addUnit ($ newUnit );
} Else {
$ Comp = new Army ();
$ Comp-> addUnit ($ occupyingUnit );
$ Com-> addUnit ($ newUnit );
}
Return $ comp;
}
}
$ Main_army = new Army ();
UnitScript: joinExisting (new Archer (), $ main_army );
UnitScript: joinExisting (new LaserCannonUnit (), $ main_army );
UnitScript: joinExisting (new Cavalry (), $ main_army );
$ Textdump = new TextDumpArmyVisitor ();
$ Main_army-> accept ($ textdump );
Print $ textdump-> getText ();
// Client code 2 (tax on each object, and the total number of outputs collected)
$ Main_army = new Army ();
UnitScript: joinExisting (new Archer (), $ main_army );
UnitScript: joinExisting (new LaserCannonUnit (), $ main_army );
UnitScript: joinExisting (new Cavalry (), $ main_army );
$ Taxcollector = new TaxCollectionVisitor ();
$ Main_army-> accept ($ taxcollector );
Print $ taxcollector-> getTax ();
// The above code is too lazy to test. Sorry! If you are interested, run debugging on your own!