改进方法
通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替
1. public class Liskov { 2. public static void main(String[] args) { 3. // TODO Auto-generated method stub 4. A a = new A(); 5. System.out.println("11-3=" + a.func1(11, 3)); 6. System.out.println("1-8=" + a.func1(1, 8)); 7. System.out.println("-----------------------"); 8. B b = new B(); 9. //因为 B 类不再继承 A 类,因此调用者,不会再 func1 是求减法 10. //调用完成的功能就会很明确 11. System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出 11+3 12. System.out.println("1+8=" + b.func1(1, 8));// 1+8 13. System.out.println("11+3+9=" + b.func2(11, 3)); 14. //使用组合仍然可以使用到 A 类相关方法 15. System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出 11-3 16. } 17. } 18. //创建一个更加基础的基类 19. class Base { 20. //把更加基础的方法和成员写到 Base 类 21. } 22. // A 类 23. class A extends Base { 24. // 返回两个数的差 25. public int func1(int num1, int num2) { 26. return num1 - num2; 27. } 28. } 29. // B 类继承了 A 30. // 增加了一个新功能:完成两个数相加,然后和 9 求和 31. class B extends Base { 32. //如果 B 需要使用 A 类的方法,使用组合关系 33. private A a = new A(); 34. //这里,重写了 A 类的方法, 可能是无意识 35. public int func1(int a, int b) { 36. return a + b; 37. } 38. public int func2(int a, int b) { 39. return func1(a, b) + 9; 40. } 41. //我们仍然想使用 A 的方法 42. public int func3(int a, int b) { 43. return this.a.func1(a, b); 44. } 45. }
开闭原则
基本介绍
1) 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
2) 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
3) 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
4) 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
代码引进
看一个画图形的功能
1. public class Ocp { 2. public static void main(String[] args) { 3. //使用看看存在的问题 4. GraphicEditor graphicEditor = new GraphicEditor(); 5. graphicEditor.drawShape(new Rectangle()); 6. graphicEditor.drawShape(new Circle()); 7. graphicEditor.drawShape(new Triangle()); 8. } 9. } 10. 11. //这是一个用于绘图的类 [使用方] 12. class GraphicEditor { 13. //接收 Shape 对象,然后根据 type,来绘制不同的图形 14. public void drawShape(Shape s) { 15. if (s.m_type == 1) 16. drawRectangle(s); 17. else if (s.m_type == 2) 18. drawCircle(s); 19. else if (s.m_type == 3) 20. drawTriangle(s); 21. } 22. 23. //绘制矩形 24. public void drawRectangle(Shape r) { 25. System.out.println(" 绘制矩形 "); 26. } 27. 28. //绘制圆形 29. public void drawCircle(Shape r) { 30. System.out.println(" 绘制圆形 "); 31. } 32. 33. //绘制三角形 34. public void drawTriangle(Shape r) { 35. System.out.println(" 绘制三角形 "); 36. } 37. } 38. 39. //Shape 类,基类 40. class Shape { 41. int m_type; 42. } 43. 44. class Rectangle extends Shape { 45. Rectangle() { 46. super.m_type = 1; 47. } 48. } 49. 50. class Circle extends Shape { 51. Circle() { 52. super.m_type = 2; 53. } 54. } 55. //新增画三角形 56. class Triangle extends Shape { 57. Triangle() { 58. super.m_type = 3; 59. } 60. }
方式 1 的优缺点
1) 优点是比较好理解,简单易操作。
2) 缺点是违反了设计模式的 ocp 原则,即对扩展开放(提供方),对修改关闭(使用方)。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码.
3) 比如我们这时要新增加一个图形种类 三角形,我们需要做如下修改,修改的地方较多
改进方法
思路:把创建 Shape 类做成抽象类,并提供一个抽象的 draw 方法,让子类去实现即可,这样我们有新的图形种类时,只需要让新的图形类继承 Shape,并实现 draw 方法即可,使用方的代码就不需要修 -> 满足了开闭原则
1. public class Ocp { 2. public static void main(String[] args) { 3. //使用看看存在的问题 4. GraphicEditor graphicEditor = new GraphicEditor(); 5. graphicEditor.drawShape(new Rectangle()); 6. graphicEditor.drawShape(new Circle()); 7. graphicEditor.drawShape(new Triangle()); 8. graphicEditor.drawShape(new OtherGraphic()); 9. } 10. } 11. 12. //这是一个用于绘图的类 [使用方] 13. class GraphicEditor { 14. //接收 Shape 对象,调用 draw 方法 15. public void drawShape(Shape s) { 16. s.draw(); 17. } 18. } 19. 20. //Shape 类,基类 21. abstract class Shape { 22. int m_type; 23. 24. public abstract void draw();//抽象方法 25. } 26. 27. class Rectangle extends Shape { 28. Rectangle() { 29. super.m_type = 1; 30. } 31. 32. @Override 33. public void draw() { 34. // TODO Auto-generated method stub 35. System.out.println(" 绘制矩形 "); 36. } 37. } 38. 39. class Circle extends Shape { 40. Circle() { 41. super.m_type = 2; 42. } 43. 44. @Override 45. public void draw() { 46. // TODO Auto-generated method stub 47. System.out.println(" 绘制圆形 "); 48. } 49. }/新增画三角形 50. 51. class Triangle extends Shape { 52. Triangle() { 53. super.m_type = 3; 54. } 55. 56. @Override 57. public void draw() { 58. // TODO Auto-generated method stub 59. System.out.println(" 绘制三角形 "); 60. } 61. } 62. 63. //新增一个图形 64. class OtherGraphic extends Shape { 65. OtherGraphic() { 66. super.m_type = 4; 67. } 68. 69. @Override 70. public void draw() { 71. // TODO Auto-generated method stub 72. System.out.println(" 绘制其它图形 "); 73. } 74. }
迪米特法则
基本介绍
1) 一个对象应该对其他对象保持最少的了解
2) 类与类关系越密切,耦合度越大
3) 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的 public 方法,不对外泄露任何信息
4) 迪米特法则还有个更简单的定义:只与直接的朋友通信
直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。