java 开闭原则(ocp)详解刨析和示例

莱莱  金牌会员 | 2024-12-14 22:15:27 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 879|帖子 879|积分 2637

part01
开闭原则(Open/Closed Principle,OCP)是面向对象编程中的一个紧张设计原则,属于SOLID原则之一。它的焦点思想是“软件实体(类、模块、函数等)应该对扩睁开放,对修改关闭”。这意味着在软件需求变化时,我们应该能够通过扩展现有代码而不是修改现有代码来实现功能的变化。
### 原则的解释
- **开放**:系统应该能够通过添加新功能或新模块来扩展,而不需要更改现有代码。
- **关闭**:现有的代码在功能上应该是稳固的,不应该因为新的需求而被修改。
### 实现方式
实现开闭原则的常见方法有:
1. **抽象类和接口**:通过定义抽象类或接口来创建可扩展的框架。
2. **多态**:利用多态性,允许通过接口或基类引用来调用子类的具体实现。
### 示例代码
以下是一个简单的示例,展示怎样使用开闭原则来设计一个图形绘制程序。
#### 违反开闭原则的实现
```java
  1. // 形状类
  2. public class Shape {
  3. public int type; // 1: 圆形, 2: 矩形
  4. public Shape(int type) {
  5. this.type = type;
  6. }
  7. }
  8. // 绘制器类
  9. public class ShapeDrawer {
  10. public void draw(Shape shape) {
  11. if (shape.type == 1) {
  12. System.out.println("Drawing a Circle");
  13. } else if (shape.type == 2) {
  14. System.out.println("Drawing a Rectangle");
  15. }
  16. }
  17. }
复制代码
 
// 使用示例
  1. public class Main {
  2. public static void main(String[] args) {
  3. Shape circle = new Shape(1);
  4. Shape rectangle = new Shape(2);
  5. ShapeDrawer drawer = new ShapeDrawer();
  6. drawer.draw(circle);
  7. drawer.draw(rectangle);
  8. }
  9. }
复制代码
在这个例子中,`ShapeDrawer`类的`draw`方法依赖于`Shape`类的实现细节。假如我们想添加新的外形,比如三角形,就需要修改`ShapeDrawer`类,这违反了开闭原则。
#### 遵循开闭原则的实现
我们可以使用接口和多态来重构这个例子,使其遵循开闭原则。
 
  1. // 形状接口
  2. public interface Shape {
  3. void draw(); // 抽象方法
  4. }
  5. // 圆形类
  6. public class Circle implements Shape {
  7. @Override
  8. public void draw() {
  9. System.out.println("Drawing a Circle");
  10. }
  11. }
  12. // 矩形类
  13. public class Rectangle implements Shape {
  14. @Override
  15. public void draw() {
  16. System.out.println("Drawing a Rectangle");
  17. }
  18. }
  19. // 三角形类
  20. public class Triangle implements Shape {
  21. @Override
  22. public void draw() {
  23. System.out.println("Drawing a Triangle");
  24. }
  25. }
  26. // 绘制器类
  27. public class ShapeDrawer {
  28. public void draw(Shape shape) {
  29. shape.draw(); // 多态调用
  30. }
  31. }
  32. // 使用示例
  33. public class Main {
  34. public static void main(String[] args) {
  35. Shape circle = new Circle();
  36. Shape rectangle = new Rectangle();
  37. Shape triangle = new Triangle();
  38. ShapeDrawer drawer = new ShapeDrawer();
  39. drawer.draw(circle);
  40. drawer.draw(rectangle);
  41. drawer.draw(triangle); // 添加新形状不需要修改ShapeDrawer
  42. }
  43. }
复制代码
 
### 代码分析
1. **接口 `Shape`**:定义了一个抽象的绘制方法 `draw()`,所有具体外形都实现了这个接口。
2. **具体外形类**:`Circle`、`Rectangle` 和 `Triangle` 类分别实现了 `Shape` 接口,提供了各自的 `draw()` 方法。
3. **绘制器类 `ShapeDrawer`**:`draw` 方法接受 `Shape` 接口类型的参数,通过多态性调用具体外形的 `draw()` 方法。
4. **扩展性**:假如需要添加新的外形,比如 `Triangle`,只需创建一个新的类实现 `Shape` 接口,而不需要修改 `ShapeDrawer` 的任何代码。
### 优势
- **可扩展性**:新增功能时只需添加新类,而不需要修改已有代码,减少了引入错误的风险。
- **维护性**:现有代码的稳固性得到了保证,维护本钱降低。
- **机动性**:通过接口和多态,系统的机动性提高,可以轻松实现差别的功能需求。
### 总结
开闭原则是软件设计中的紧张原则,通过合理地使用抽象类和接口,可以使系统在面对需求变化时,能够扩展而不必修改现有代码。遵循这个原则可以提高代码的可维护性、可扩展性和机动性,是构建高质量软件的关键。
 part02
让我们更详细地探讨开闭原则(OCP),并考虑更多的情况和例子。
### 开闭原则的深入分析
开闭原则夸大的是在需求变化时,应该尽量避免对已实现代码的修改。这可以通过以下几种方式实现:
1. **使用抽象类和接口**:通过定义接口或抽象类来提供同一的举动。
2. **策略模式**:通过定义一系列算法,将它们封装起来,使它们可以互相更换,从而使算法的变化独立于使用算法的客户端。
3. **工厂模式**:使用工厂模式来创建对象,从而使对象的创建与使用分离。
4. **变乱驱动架构**:通过变乱和观察者模式来实现系统的松耦合。
### 示例:图形绘制程序的多种实现
#### 1. 初始实现(违反开闭原则)
  1. // 形状类
  2. public class Shape {
  3. public int type; // 1: 圆形, 2: 矩形
  4. public Shape(int type) {
  5. this.type = type;
  6. }
  7. }
  8. // 绘制器类
  9. public class ShapeDrawer {
  10. public void draw(Shape shape) {
  11. if (shape.type == 1) {
  12. System.out.println("Drawing a Circle");
  13. } else if (shape.type == 2) {
  14. System.out.println("Drawing a Rectangle");
  15. }
  16. // 如果要添加新的形状,比如三角形,需要修改此处
  17. }
  18. }
复制代码
 
#### 2. 使用接口和多态的实现(遵循开闭原则)
  1. // 形状接口
  2. public interface Shape {
  3. void draw(); // 抽象方法
  4. }
  5. // 圆形类
  6. public class Circle implements Shape {
  7. @Override
  8. public void draw() {
  9. System.out.println("Drawing a Circle");
  10. }
  11. }
  12. // 矩形类
  13. public class Rectangle implements Shape {
  14. @Override
  15. public void draw() {
  16. System.out.println("Drawing a Rectangle");
  17. }
  18. }
  19. // 三角形类
  20. public class Triangle implements Shape {
  21. @Override
  22. public void draw() {
  23. System.out.println("Drawing a Triangle");
  24. }
  25. }
  26. // 绘制器类
  27. public class ShapeDrawer {
  28. public void draw(Shape shape) {
  29. shape.draw(); // 多态调用
  30. }
  31. }
  32. // 使用示例
  33. public class Main {
  34. public static void main(String[] args) {
  35. Shape circle = new Circle();
  36. Shape rectangle = new Rectangle();
  37. Shape triangle = new Triangle();
  38. ShapeDrawer drawer = new ShapeDrawer();
  39. drawer.draw(circle);
  40. drawer.draw(rectangle);
  41. drawer.draw(triangle); // 添加新形状不需要修改ShapeDrawer
  42. }
  43. }
复制代码
 
### 进一步扩展:策略模式和工厂模式
#### 3. 使用策略模式
假设我们希望根据差别的绘图策略来绘制外形,而不是在 `ShapeDrawer` 中硬编码每种外形的绘制逻辑。
  1. // 绘制策略接口
  2. public interface DrawStrategy {
  3. void draw();
  4. }
  5. // 圆形绘制策略
  6. public class CircleDrawStrategy implements DrawStrategy {
  7. @Override
  8. public void draw() {
  9. System.out.println("Drawing a Circle");
  10. }
  11. }
  12. // 矩形绘制策略
  13. public class RectangleDrawStrategy implements DrawStrategy {
  14. @Override
  15. public void draw() {
  16. System.out.println("Drawing a Rectangle");
  17. }
  18. }
  19. // 三角形绘制策略
  20. public class TriangleDrawStrategy implements DrawStrategy {
  21. @Override
  22. public void draw() {
  23. System.out.println("Drawing a Triangle");
  24. }
  25. }
  26. // 形状类
  27. public class Shape {
  28. private DrawStrategy drawStrategy;
  29. public Shape(DrawStrategy drawStrategy) {
  30. this.drawStrategy = drawStrategy;
  31. }
  32. public void draw() {
  33. drawStrategy.draw();
  34. }
  35. }
  36. // 使用示例
  37. public class Main {
  38. public static void main(String[] args) {
  39. Shape circle = new Shape(new CircleDrawStrategy());
  40. Shape rectangle = new Shape(new RectangleDrawStrategy());
  41. Shape triangle = new Shape(new TriangleDrawStrategy());
  42. circle.draw();
  43. rectangle.draw();
  44. triangle.draw(); // 添加新策略不需要修改Shape
  45. }
  46. }
复制代码
 
### 4. 使用工厂模式
工厂模式可以用于创建外形对象,从而将对象的创建与使用分离。
  1. // 形状工厂接口
  2. public interface ShapeFactory {
  3. Shape createShape();
  4. }
  5. // 圆形工厂
  6. public class CircleFactory implements ShapeFactory {
  7. @Override
  8. public Shape createShape() {
  9. return new Shape(new CircleDrawStrategy());
  10. }
  11. }
  12. // 矩形工厂
  13. public class RectangleFactory implements ShapeFactory {
  14. @Override
  15. public Shape createShape() {
  16. return new Shape(new RectangleDrawStrategy());
  17. }
  18. }
  19. // 三角形工厂
  20. public class TriangleFactory implements ShapeFactory {
  21. @Override
  22. public Shape createShape() {
  23. return new Shape(new TriangleDrawStrategy());
  24. }
  25. }
  26. // 使用示例
  27. public class Main {
  28. public static void main(String[] args) {
  29. ShapeFactory circleFactory = new CircleFactory();
  30. ShapeFactory rectangleFactory = new RectangleFactory();
  31. ShapeFactory triangleFactory = new TriangleFactory();
  32. Shape circle = circleFactory.createShape();
  33. Shape rectangle = rectangleFactory.createShape();
  34. Shape triangle = triangleFactory.createShape();
  35. circle.draw();
  36. rectangle.draw();
  37. triangle.draw(); // 添加新形状只需新建工厂类
  38. }
  39. }
复制代码
 
### 5. 变乱驱动架构
假如我们希望在绘制外形时能够触发变乱,可以使用变乱驱动架构。我们可以定义一个变乱监听器接口,并在绘制时触发变乱。
  1. // 事件监听器接口
  2. public interface DrawListener {
  3. void onDraw();
  4. }
  5. // 形状类
  6. public class Shape {
  7. private DrawStrategy drawStrategy;
  8. private DrawListener listener;
  9. public Shape(DrawStrategy drawStrategy, DrawListener listener) {
  10. this.drawStrategy = drawStrategy;
  11. this.listener = listener;
  12. }
  13. public void draw() {
  14. if (listener != null) {
  15. listener.onDraw(); // 触发事件
  16. }
  17. drawStrategy.draw();
  18. }
  19. }
  20. // 使用示例
  21. public class Main {
  22. public static void main(String[] args) {
  23. Shape circle = new Shape(new CircleDrawStrategy(), () -> System.out.println("Circle is being drawn"));
  24. Shape rectangle = new Shape(new RectangleDrawStrategy(), () -> System.out.println("Rectangle is being drawn"));
  25. circle.draw();
  26. rectangle.draw(); // 事件被触发
  27. }
  28. }
复制代码
 
### 总结
通过深入分析开闭原则,我们可以发现它在软件设计中的紧张性。遵循开闭原则可以让我们的代码更加机动、可维护和可扩展。无论是通过接口、抽象类、策略模式照旧工厂模式,大概联合变乱驱动架构,我们都可以实现这一原则。
1. **机动性**:可以轻松添加新功能,而不需要修改现有代码。
2. **降低耦合**:通过接口和抽象类,系统的各个部分相互独立。
3. **提高可维护性**:现有代码的稳固性得以保证,维护本钱降低。
通过这些示例,可以看到怎样在实际开发中应用开闭原则,以构建更高质量的软件系统。
更多实用教程资源
http://sj.ysok.net/jydoraemon 访问码:JYAM

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莱莱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表