Design pattern - Richter replacement

Keywords: less

Let's start with the most authentic definition If there is object o2 of type T for each object o1 of type S, so that when all object o1 defined by T is replaced by o2, the behavior of program P does not change, then type S is a subtype of type T. Let's look at a simple definition: All references to base classes must be able to use objects of their subclasses transparently. Let's take a look at the uml diagram

public abstract class AbstractGun {
    //What's the gun for? Kill the enemy!
    public abstract void shoot();
}    
//The implementation classes of pistol, rifle and machine gun are shown in listing 2-2. Code listing 2-2 implementation class of pistol, rifle and machine gun
public class Handgun extends AbstractGun { 
    //The pistol is easy to carry and has a short range
    @Override
    public void shoot() {
        System.out.println("Pistol shooting...");
    } 
}
public class Rifle extends AbstractGun{ 
    //The characteristics of rifles are long range and powerful
    public void shoot(){
        System.out.println("Rifle shooting...");
    } 
}
public class MachineGun extends AbstractGun{ 
    public void shoot(){
        System.out.println("Machine gun fire...");
    }
}
//With guns, there must be soldiers who can use these guns, and their source programs, such as soldiers' implementation classes
public class Soldier { 
    //Defining a soldier's gun
    private AbstractGun gun;
    //Give the soldier a gun
    public void setGun(AbstractGun _gun){
        this.gun = _gun;
    }

    public void killEnemy(){
        System.out.println("The soldiers began to kill the enemy..."); 
        gun.shoot();
    } 
}
//It is defined that soldiers use guns to kill enemies, but this gun is abstract. Whether it is a pistol or a rifle needs to be determined by setGun method before going to the battlefield (that is, in the scene)
public class Client {
    public static void main(String[] args) {
        //Produce Sanmao, the soldier
        Soldier sanMao = new Soldier(); 
        //Give Sanmao a gun
        sanMao.setGun(new Rifle()); 
        sanMao.killEnemy();
    } 
}

Some special subclasses will inevitably be encountered in the project, so it is recommended to use aggregation or combination

For example, as follows

public class ToyGun extends AbstractGun { 
    //The toy gun can't shoot, but the compiler requires to implement this method. What should I do? Make up one! 
    @Override
    public void shoot() {
    //If the toy gun can't shoot, this method will not be realized
    } 
}
public class Client {
    public static void main(String[] args) {
        //Produce Sanmao, the soldier
        Soldier sanMao = new Soldier(); 
		sanMao.setGun(new ToyGun()); 
		sanMao.killEnemy();
    } 
}

In this case, the following methods are recommended Let's also look at the uml diagram

public class AUG extends Rifle { 
    //Sniper guns carry a precise telescope 
    public void zoomOut(){
        System.out.println("Look at the enemy through a telescope..."); 
		public void shoot(){
       		System.out.println("AUG Shooting...");
    } 
} 
public class Snipper {
    public void killEnemy(AUG aug){
        //First of all, look at the situation of the enemy. Don't kill the enemy. You will also be killed by others 
		aug.zoomOut();
        //Start shooting
        aug.shoot();
    } 
}
public class Client {
    public static void main(String[] args) {
        //Generate Sanmao, the sniper
        Snipper sanMao = new Snipper(); 
        sanMao.setRifle(new AUG()); 
        sanMao.killEnemy();
    } 
}

In order to meet the design requirements of the "Richter replacement" principle, the subclass cannot have too much personality. When the subclass overloads the method of the parent, the input parameter should be broader, greater than or equal to the parent, and the return value should be contracted, less than or equal to the parent. Let's take a look at the specific code description

public class Father {
    public Collection doSomething(HashMap map){
        System.out.println("Parent class is executed..."); 
        return map.values();
    }
}
public class Son extends Father { 
    //Enlarge input parameter type
    public Collection doSomething(Map map){ 
        System.out.println("Subclass is executed..."); 
        return map.values();
    } 
}
public class Client {
    public static void invoker(){
        //Where the parent exists, the child should be able to exist 
        Father f = new Father(); 
        HashMap map = new HashMap(); 
        f.doSomething(map);
    }
    public static void main(String[] args) {
        invoker();
    } 
}

Welcome to my official account.

Posted by gman-03 on Mon, 06 Apr 2020 07:04:07 -0700