Six principles of the design model (2)-the principle of replacement

Source: Internet
Author: User
Tags define abstract

Definition:

Objects in a program should be replaced by its subclass without changing the program's correctness. That is to say, all objects that reference the base class must be transparently used. In general, child classes can extend the functions of the parent class, but cannot change the original functions of the parent class.

Origin:

The first time I saw the name of this Lee's replacement principle, I felt very strange. According to my previous experience, this was the first concept proposed by a foreign friend. Then I named it by her surname. Indeed, it was first proposed by Barbara liskov in a speech titled "data abstraction and hierarchy" at a conference in 1987. The default English name is liskov substitution principle. Therefore, LSP is short for this principle.

In-depth:

The Lee replacement principle defines a standard for good inheritance. A simple definition contains four meanings:

  • Subclass must fully implement the parent class Method

When designing a system, we often write interfaces and abstract classes, and then encode them to inherit them. In fact, here we have applied the Lee's replacement principle. For example, we can simply implement various guns in CS (define abstract classes and then inherit from them). The gun class diagram is as follows:

A gun is primarily responsible for killing people. Each gun has its own characteristics. Shou is a single-shot gun with a short range. It has a high range of far-Force and is mainly used for scanning. At the same time, a soldier class is defined. The killenemy (abstractgun gun) method uses a gun to kill people. It is only known when a gun is called.

The following describes the implementation of the gun abstract class, common gun, and soldier code:

/// <Summary> // gun abstract class // </Summary> public abstract class implements actgun {public abstract void shoot ();} /// <summary> /// Shou gun /// </Summary> public class handgun: abstractgun {public override void shoot () {console. writeline ("Shou gun shot... ") ;}//< summary> /// rifle /// </Summary> public class rifle: abstractgun {public override void shoot () {console. writeline ("rifle shot... ") ;}/// <summary> /// machine gun // </Summary> public class machinegun: abstractgun {public override void shoot () {console. writeline ("Machine gun shooting... ") ;}/// <summary> // soldier class /// </Summary> public class solder {public void killenemy (abstractgun gun) {console. writeline ("soldiers start killing... "); gun. shoot ();}}

The scenario class (main function) code is as follows:

class Client    {        static void Main(string[] args)        {            var solder = new Solder();            solder.KillEnemy(new Rifle());            Console.ReadKey();        }     }

The running result is as follows:

In this program, we gave the sanmao soldier a rifle and then began to kill the enemy. If sanmao wanted to use a machine gun, of course, it would be okay to directly put solder. change killenemy (new rifle () to solder. killenemy (New machinegun () can be used. When programming, solider soldiers do not need to know which type of gun (subclass) is passed in.

Note that it is necessary to use the parent class or interface when calling other classes in the class. If the parent class or interface cannot be used, it indicates that the class design has violated the LSP principle.

If we want to marry a toy gun now, we will add a tonygun class to inherit abstractgun. After adding the toy gun, the new class is shown as follows:

However, considering the actual situation, because a toy gun generally kills no one, the class in the toy gun cannot kill people. As shown in the following code, this method can only be left blank:

/// <Summary> /// toy gun /// </Summary> public class tonygun: abstractgun {public override void shoot () {// the toy gun cannot be shot, this cannot be implemented here }}

The Demo code is as follows:

class Client    {        static void Main(string[] args)        {            var solder = new Solder();            solder.KillEnemy(new TonyGun());            Console.ReadKey();        }     }

The running result is as follows:

As a result, only the soldiers were prompted to kill, but no bullets were fired (because they were using a toy gun, a little involved ).

In this case, we find that the service calling class has encountered a problem and the normal business logic is no longer running. What should we do? There are two solutions:

1. Add the instanceof judgment in the soldier class. If it is a toy gun, it will not be used to kill the enemy. This method can solve the problem, but you need to know that every time a class is added in the program, all classes related to this parent class must be modified. Do you think this method is feasible? If this problem occurs in your product, because you have fixed such a bug, you need to add a judgment for all the classes related to this parent class. The customer cannot jump up and fight with you! Do you still want your customers to be loyal to you? Apparently, this solution was rejected.

2. toygun disconnects from inheritance and establishes an independent parent class. In order to reuse code, it can establish an association with abastractgun.
 

Note: If the subclass cannot fully implement the parent class method, or some methods of the parent class have been "distorted" in the subclass, we recommend that you disconnect the Parent-Child inheritance relationship, inheritance is replaced by dependency, aggregation, and combination.

 

  • Subclass can have its own personality

Sub-classes can certainly have their own behaviors and appearances (that is, methods and attributes). Why do we mention them here? Because the Rys replacement principle cannot be used here, child classes can replace parent classes, but parent classes cannot replace parent classes (if they can be replaced, there is no need to derive child classes ), I will not explain the specifics (the definition is so simple, and the principle is quite simple). I will give a brief description using the following figure:

  • When overwriting or implementing the parent class method, the input parameter can be enlarged.

The input parameters in the method are called preconditions. What does this mean? After web service development, you should know that there is a "contract first" principle, that is, the WSDL interface is defined first, and the Development protocols of both parties are developed before implementation. The lean replacement principle also requires a contract, that is, a parent class or interface. This design method is also called design by contract. Contract Design is integrated with the lean replacement principle. After the contract is formulated, both the preconditions and the postcondition are set. The precondition is that if you want me to execute the statement, you must satisfy my conditions. The latter condition is that I need feedback after the execution, what is the standard.

If the subclass method does not overwrite the parent class method, the subclass method is executed, which will cause confusion in the business logic, because in actual applications, the parent class is generally an abstract class, subclass is an implementation class. If you pass such an implementation class, it will "distort" the intent of the parent class, causing unexpected business logic confusion, therefore, the preconditions of the method in the subclass must be the same or loose as those of the method covered in the superclass..

  • Output results can be reduced when override or parent classes are implemented.

What does this mean? The Return Value of a method of the parent class is a type T, and the return value of the same method (overload or overwrite) of the subclass is S, in this case, the replacement principle requires s to be less than or equal to T, that is, either S and T are of the same type or S is a subclass of T. Why? In two cases, if it is overwriting, the input parameters of the methods with the same name as the parent class and subclass are the same, and the range value s of the two methods is less than or equal to T, which is the overwriting requirement, this is the top priority. sub-classes override the parent class method. If it is a heavy load, the input parameter type or quantity of the method must be different. In the requirements of the Rys replacement principle, the input parameter of the subclass is greater than or equal to the input parameter of the parent class, that is to say, the method you write will not be called. Refer to the prerequisites mentioned above.
The purpose of adopting the Lee's replacement principle is to enhance the robustness of the program, and maintain excellent compatibility during version upgrades. Even if a subclass is added, the original subclass can continue to run. In actual projects, each subclass corresponds to different business meanings. It is perfect to use the parent class as a parameter to pass different subclasses to complete different business logic!

Summary:

It looks incredible, because we will find that in our own programming, we often violate the Lee's replacement principle, and the program runs well. So everyone will have such questions. What would happen if I did not follow the Lee's replacement principle?
The consequence is that the chances of problems with the code you write will be greatly increased.

PS: at the end of the submission, I was prompted that the [hand-gun] was a prohibited word, so I had to change it to the Shou gun.

Six principles of the design model (2)-the principle of replacement

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.