Solution: Decoupling implementation from the objects that use them.
public abstract class AbstractShape { private DrawingProgram dp; public abstract void draw(); public AbstractShape(DrawingProgram dp) { this.dp = dp; } public void drawLine() { this.dp.drawLine(); } public void drawCircle() { this.dp.drawCircle(); } }
public class Rectangle extends AbstractShape { public Rectangle(DrawingProgram dp) { super(dp); } @Override public void draw() { drawLine(); drawLine(); drawLine(); drawLine(); } }
public class Circle extends AbstractShape { public Circle(DrawingProgram dp) { super(dp); } @Override public void draw() { drawCircle(); } }
public interface DrawingProgram { void drawLine(); // implicitly public void drawCircle(); }
public class DrawingProgram1 implements DrawingProgram { @Override public void drawLine() { ... } @Override public void drawCircle() { ... } }
public class DrawingProgram2 implements DrawingProgram { @Override public void drawLine() { ... } @Override public void drawCircle() { ... } }
public class client { public static void main(String[] args) { Drawing dp1 = new DrawingProgram1(); Rectangle rectangle = new Rectangle(dp1); Drawing dp2 = new DrawingProgram2(); Circle circle = new Circle(dp2); circle.draw(); rectangle.draw(); } }