1. Design case:
Design an object (duck) that can swim, bark, eat, jump, color, etc.
General design method:
Define a super class in which common properties are defined
Write various subclasses, all inherit the superclass and define its special attributes
Requirement Change 1: Add a duck function to make ducks fly
Modification method: define the properties of the fly in the super class and provide the implementation
Problem: Not all ducks need to fly, such as wood ducks; a single stroke can move the whole body
Requirements change a new design: add fly interface
Implementation result: let the flying duck implement the interface
Problem: The code repeats infinitely (because all subclasses that inherit this interface need to implement this method)
Well, let's do this for now, it's troublesome, but he can run
Requirement Change 2: Let the ducks realize different flight modes
Implementation result: Modify all implementation classes that inherit the interface
Question: Who knows if you are missing the implementation of that subclass
Well, although it is troublesome, at least it is not realized, then the result of such a design is as follows:
public class Duck{ public void eat(){} public void display(){} } public interface fly{ void fly(); } public class RedDuck extends Duck implements fly{ ... } public class GreenDuck extends Duck implements fly{ ... } public class WoodDuck extends Duck{ ... }
Problem: With the change of requirements, the code will be further complicated, maintenance is troublesome, and the code cannot be reused, and it is easy to miss when modifying.
To sum up: This design pattern is not desirable in frequently changing requirements.
Better solution: For interface programming, extract the parts that are easy to change, encapsulate, realize code reuse, and system flexibility.
code show as below:
public class Duck{ //Define interface properties, use polymorphism to dynamically call different implementations Fly fly; Call call; //Provide get set method, the purpose is to change its implementation dynamically at any time through set in the future ....get/set //Provide methods to dynamically call different implementations public void performFly(){ fly.fly(); } public void performCall(){ call.call(); } public void eat(){} public void display(){} } //Extract frequently changing properties into interfaces, and complete unreasonable changes by implementing these interfaces public interface Fly{ public void fly(); } public interface Call{ public void call(); } public class FlyWithWings implements fly{ public void fly(){ System.out.println("can fly"); } } public class FlayNoWay implements fly{ public void fly(){}//Can't fly, do nothing here } public class call1 implements call{ public void call(){ System.out.println("call 111"); } } public class call2 implements call{ public void call(){ System.out.println("call 222"); } } //Dynamic call method public class RedDuck extends Duck{ //Define the implementation class of the dynamic call through the constructor public RedDuck(){ fly = new FlyWithWings(); call = new Call1(); } }