Policy mode-dynamic algorithm change

Source: Internet
Author: User

Policy pattern is an important design pattern. Its main intention is to defineAlgorithmRespectively, so that they can be replaced with each other. It allows algorithm changes to be independent of algorithm customers, so that we can change them at any time without affecting the client'sCodeThe client can select different algorithms for execution.

To understand the policy model, we need to understand several important concepts:

1. What is a policy? 2. What is an algorithm? 3. What are the conditions for algorithm replacement? A policy refers to a plan or scheme for achieving a certain target under a given input condition. An algorithm is a defined process that generates an output based on a set of inputs. The two can be understood as follows: the policy is a set of replaceable algorithms. Algorithms that can be replaced with each other must have the same characteristics, that is, they process the same source and destination of objects, and do not require the same object type. After understanding the differences between policies and algorithms, we will discuss several important aspects of the policy model: 1. What are the reasons for using the policy model? 2. Implementation of policy mode? 3. What are the advantages and disadvantages of the Policy mode? Why should we use the policy mode? Think about this situation. We are responsible for recording the data of a base fighter. The fighter has various models and performances, and the weapons and flight modes in performance are various. However, we provide only two interfaces: fly () and attack (). To show the performance of different fighters in these two methods, we may use inheritance. First, we will define an abstract class: plane, which looks like the following:
Public Abstract ClassPlane {Private Abstract VoidFly ();Private Abstract VoidAttack ();}

Then we will start to define some specific types of fighters:

       Public Class rocketplaneExtends  Plane {  Private   Void  Fly () {system. Out. println ( "This plane fly with Rocket" );}  Private   Void  Attack () {system. Out. println ( "This plane attack with fire" );}}  Public   Class Windplane Extends Plane {  Private   Void  Fly () {system. Out. println ( "This plane fly with wind" );}  Private   Void  Attack () {system. Out. println ( "This plane attack with Rocket" );}} 

in our Program , write:

  Public   static   void   main (string [] ARGs) {rocketplane plane1  =  New   rocketplane (); windplane plane2  =  New   windplane (); showfunctionofplane (plane1); showfunctionofplane (plane2 );}   private   void   showfunctionofplane (plane) {plane. fly (); plane. attack () ;} 

Inheritance can solve this problem, but inheritance also has its own problems. The biggest problem with inheritance is that the changes to the base class will be passed to all the sub-classes, which we do not want to see. So, if we don't use inheritance, we can do it? Interface is the best alternative in this case.

By using interfaces, our code can be more flexible. Interface is a good thing, but how to use it is also an important question, that is, what should we make an interface? If we use the abstraction of the fighter plane as an interface, such:

 
PublicInterface plane {VoidFly ();VoidAttack ();}

in this way, the specific implementation is handed over to the implementation class to avoid the above problems. This is true, but the basic things remain unchanged even if there is a big gap in the appearance of different types of fighters, such as the basic attributes of weight, will not change for at least a long time, if an interface is used, we cannot set some common attributes and Methods. Of course, we can assign such a thing to the implementation class for implementation. In this way, code duplication is terrible!

Abstract classes still have the advantages of abstract classes, and interfaces cannot be completely replaced, just like the above example. The interface is abused to a large extent because it is a very useful thing, especially the use of polymorphism. But the design of the class should be close to the real life. Just like the above example of a fighter, we abstract such things as a fighter, and the code should reflect the programmer's thinking on a problem, it is not just a byte code that is handed to the computer for processing. Misuse of interfaces is a breach of this principle, because many people do not know the true meaning of interfaces. Abstract classes are used to express the "is-a" relationship, while interfaces are used to express the "has-a" relationship. Inherited from an abstract class, the subclass itself is a special case of the abstract class. It belongs to the abstract class in terms of classification, but it does not mean implementing an interface. Our implementation class is an interface, the accurate statement is that our implementation class has the behavior defined by this interface. Of course, for type recognition, the interface and the abstract class are no different, and they are all the abstraction of a thing. The real meaning of an interface is a set of behavior protocols that define the behavior that our implementation class should have. Some people may say that this is a "is-like-a" relationship. This is a mistake in the "is-like-a" relationship, the "is-like-a" relationship also belongs to an inherited relationship. in the traditional sense, the inheritance should be completely inherited, that is, no new functions are added, only override the methods of the base class so that the sub-classes can be transformed to the base class without errors. However, the reality is that the sub-classes have their own behaviors and have their own unique attributes and behaviors, this makes them unable to transform upwards. This is the "is-like-a" relationship. After understanding the logical meaning of interfaces and abstract classes, we can decide what type of abstraction should be used according to real life during design. In the above example, we still use abstract classes because we need a place to store the attributes and behaviors of all fighters. abstract classes are a good choice. Next, we will extract the modified behavior as an interface. How can we determine whether a behavior should be extracted? If we modify this behavior, do we need to modify other code? if necessary, this shows that this behavior is a changing factor. Here we extract the flight and attack actions. Now we extract the flight and attack interfaces:
 PublicInterface flyable {VoidFly ();}PublicInterface attackable {VoidAttack ();}
Here we may make a mistake like this:
          Public   Class Rocketplane Extends PlaneImplements  Flyable, attackable {  Void  Fly (){
System. Out. println ("this plane fly with Rocket");
} Void Attack (){
System. Out. println ("this plane attack with fire");
}} Public Class Windplane Extends Plane Implements Flyable, attackable { Void Fly (){
System. Out. println ("this plane fly with wind"); 
} Void Attack (){
System. Out. println ("this plane attack with Rocket"); 
}}

Why is it written like this? It is very simple, because some of us may not be able to fly at all, like this:

Public ClassNotflyplaneExtendsPlaneImplementsAttackable {VoidAttack (){
System. Out. println ("this plane attack with wind ");
}}

 However, we do not need our subclass to implement these interfaces at all. The greater significance of interfaces is the combination of objects. In this way, the advantages of interfaces are lost. To use these advantages of interfaces, we can establish the implementation class groups of these two interfaces as follows:

            Public   Class Flywithrocket Implements  Flyable {  Void  Fly (){
System. Out. println ("this plane fly with Rocket ");
}}
Public Class Attackwithrocket Implements Attackable { Void attack () {
system. out. println ("this plane attack with Rocket");
}< br>
public class flywithwind implements flyable {
void fly () {
system. out. println ("this plane fly with wind");
}< BR >}< br>
public class attackwithfire implements attackable {
void attack () {
system. out. println ("this plane attack with fire");
}< BR >}< br>
public class notfly implements flyable {
void fly () {
system. out. println ("This plane can't fly");
}< BR >}< br>

then use these Implementation classes in our code:

 public abstract class plane () {
protected flyable mfly;
protected attackable mattack;
protected abstract void description ();
protected void functiontest () {
mfly. fly ();
mattack. attack ();
}< BR >}< br> Public class rocketplane extends plane {rocketplane () {
super. mfly = New flywithrocket (); super. mattack = new attackwithfire ();
}< br> protected void description () {
system. out. println ("I Am a rocketplane ");
}< BR >}< br>
public class test {
Public static void main (string [] ARGs) {
rocketplane plane = new rocketplane ();
plane. functiontest ();
}< BR >}

This is the method of object combination, but this method is not elegant enough. At this time, the policy mode was officially launched, because it is a mode for processing object combinations.

The abstract class can be modified as follows:

Public abstract class plane {

Private flyable mfly;

Private attackable mattack;

Plane (){}

Plane (flyable fly, attackable attack ){

This. mfly = fly;

This. mattack = attack;

}

Protected abstract void description ();

Protected void setfly (flyable fly ){

This. mfly = fly;

}

Protected void setattack (attackable attack ){

This. mattack = attack;

}

Protected void testfunction (){

Description ();

Mfly. Fly ();

Mattack. Attack ();

}

}

Next is our subclass and test class:

Public class rocketplane extends plane {

Rocketplane (){}

Rocketplane (flyable fly, attackable attack ){

Super (fly, attack );

}

@ Override

Protected void description (){

System. Out. println ("I Am a rocketplane ");

}

}

Public class test {

Public static void main (string [] ARGs ){

Rocketplane plane = new rocketplane (New flywithrocket (), new attackwithfire ());

Plane. testfunction ();

}

}

If the flight capability of a fighter plane changes, we can dynamically change its behavior, such:
 
Plane. setfly (New flywithwind ());
In this way, it will change from rocket injection to flying by wing !! In addition, our customers can change their flight capabilities at any time, as long as they like it or even do not have the flight capabilities. The above is the standard usage of the Rule mode, which fully reflects the intention of the Rule mode. However, the inheritance problem still exists, and the changes of the base class will still be passed to the subclass. Therefore, we must ensure that, the non-Abstract part of the base class remains unchanged for a long time. The composition of the Policy mode actually includes an environment (context) class, which has abstract reference of the policy, and can change the policy and execute the policy at any time. In the above example, the abstract class seems to be an environment role class, but the method that determines the dynamic execution of the policy is subclass, And the subclass is the real context. The true significance of the Environment role class is the specific application environment of the policy, which is undoubtedly a specific subclass. The policy mode can also be linked to the delegate. In the preceding example, we create a delegate class:
  Public   class   functiontest {  private   plane mplane; functiontest (plane) {  This . mplane =  plane ;}  void   functiontest () {plane. testfunction () ;}< br> 
public class test {
Public static void main (string [] ARGs) {
rocketplane plane = new rocketplane (New flywithrocket (), new attackwithfire ();
functiontest test = new functiontest (plane);
test. functiontest ();
}< BR >}

what are the advantages of using the delegate class? The delegate class provides an indirect layer. We don't need to know the details about the fighter plane. We only know that using functiontest () can let our fighter plane fly and attack the enemy. This is encapsulation. The customer only knows to call the methods provided by the delegate class, even if the internal structure of the fighter plane changes, such as testfunction () to function (), what is the relationship with our customer code?

At this point, the basic content of the Policy mode has been completed. By using interfaces to implement object combination, we can fully implement code reuse. Do implementation rule modes really need to be inherited? Not necessarily, because the policy mode is only used to encapsulate a group of algorithm families and then implement algorithm replacement. To achieve this goal, it can be said that it is a policy mode. After introducing the rule mode, the last part is to answer the three questions we raised above: 1. Why is the rule mode used? The reason is the same as the intention. Some books may say that the policy mode is to deal with if... else if... else is a large number of conditional statement blocks, but do not use the policy mode as prompted. Although the algorithm is replaced here, we may not be able to completely remove these condition judgments. We are sure that we can encapsulate these codes, especially the repetitive code in similar algorithms. However, this is not what the rule mode should do. Its greater role is to dynamically change the algorithm at runtime, and to hand over the implementation of the algorithm to specific sub-classes for implementation, designers of our classes do not need to think too much about future changes, as long as they leave room for future changes. 2. Implementation of policy mode? There are various implementation modes, but the basic idea will not change. Different Languages and situations can adopt different implementation modes. 3. What are the advantages and disadvantages of the Policy mode? The advantage is its intention and disadvantage? This is hard to explain, because in most cases, the shortcomings of the mode are incorrect usage modes, and cannot be attributed to the mode itself. The biggest drawback of the Rule mode is that we need to maintain a large number of classes, but this problem can be solved using the factory method mode. Finally, we paste the UML diagram of the above example. The UML diagram of the Policy mode is like this:

 

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.