首页 > 编程语言 >java 开闭原则(ocp)详解刨析和示例

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

时间:2024-12-14 23:31:28浏览次数:3  
标签:draw java 示例 刨析 class Shape void new public

part01

开闭原则(Open/Closed Principle,OCP)是面向对象编程中的一个重要设计原则,属于SOLID原则之一。它的核心思想是“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭”。这意味着在软件需求变化时,我们应该能够通过扩展现有代码而不是修改现有代码来实现功能的变化。

### 原则的解释

- **开放**:系统应该能够通过添加新功能或新模块来扩展,而不需要更改现有代码。
- **关闭**:现有的代码在功能上应该是稳定的,不应该因为新的需求而被修改。

### 实现方式

实现开闭原则的常见方法有:

1. **抽象类和接口**:通过定义抽象类或接口来创建可扩展的框架。
2. **多态**:利用多态性,允许通过接口或基类引用来调用子类的具体实现。

### 示例代码

以下是一个简单的示例,展示如何使用开闭原则来设计一个图形绘制程序。

#### 违反开闭原则的实现

```java

// 形状类
public class Shape {
public int type; // 1: 圆形, 2: 矩形

public Shape(int type) {
this.type = type;
}
}

// 绘制器类
public class ShapeDrawer {
public void draw(Shape shape) {
if (shape.type == 1) {
System.out.println("Drawing a Circle");
} else if (shape.type == 2) {
System.out.println("Drawing a Rectangle");
}
}
}

 

// 使用示例

public class Main {
public static void main(String[] args) {
Shape circle = new Shape(1);
Shape rectangle = new Shape(2);
ShapeDrawer drawer = new ShapeDrawer();

drawer.draw(circle);
drawer.draw(rectangle);
}
}

在这个例子中,`ShapeDrawer`类的`draw`方法依赖于`Shape`类的实现细节。如果我们想添加新的形状,比如三角形,就需要修改`ShapeDrawer`类,这违背了开闭原则。

#### 遵循开闭原则的实现

我们可以使用接口和多态来重构这个例子,使其遵循开闭原则。

 

// 形状接口
public interface Shape {
void draw(); // 抽象方法
}

// 圆形类
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}

// 矩形类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}

// 三角形类
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Triangle");
}
}

// 绘制器类
public class ShapeDrawer {
public void draw(Shape shape) {
shape.draw(); // 多态调用
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
Shape rectangle = new Rectangle();
Shape triangle = new Triangle();

ShapeDrawer drawer = new ShapeDrawer();

drawer.draw(circle);
drawer.draw(rectangle);
drawer.draw(triangle); // 添加新形状不需要修改ShapeDrawer
}
}

 

### 代码分析

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. 初始实现(违反开闭原则)

// 形状类
public class Shape {
public int type; // 1: 圆形, 2: 矩形

public Shape(int type) {
this.type = type;
}
}

// 绘制器类
public class ShapeDrawer {
public void draw(Shape shape) {
if (shape.type == 1) {
System.out.println("Drawing a Circle");
} else if (shape.type == 2) {
System.out.println("Drawing a Rectangle");
}
// 如果要添加新的形状,比如三角形,需要修改此处
}
}

 

#### 2. 使用接口和多态的实现(遵循开闭原则)

// 形状接口
public interface Shape {
void draw(); // 抽象方法
}

// 圆形类
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}

// 矩形类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}

// 三角形类
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Triangle");
}
}

// 绘制器类
public class ShapeDrawer {
public void draw(Shape shape) {
shape.draw(); // 多态调用
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
Shape rectangle = new Rectangle();
Shape triangle = new Triangle();

ShapeDrawer drawer = new ShapeDrawer();

drawer.draw(circle);
drawer.draw(rectangle);
drawer.draw(triangle); // 添加新形状不需要修改ShapeDrawer
}
}

 

### 进一步扩展:策略模式和工厂模式

#### 3. 使用策略模式

假设我们希望根据不同的绘图策略来绘制形状,而不是在 `ShapeDrawer` 中硬编码每种形状的绘制逻辑。

// 绘制策略接口
public interface DrawStrategy {
void draw();
}

// 圆形绘制策略
public class CircleDrawStrategy implements DrawStrategy {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}

// 矩形绘制策略
public class RectangleDrawStrategy implements DrawStrategy {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}

// 三角形绘制策略
public class TriangleDrawStrategy implements DrawStrategy {
@Override
public void draw() {
System.out.println("Drawing a Triangle");
}
}

// 形状类
public class Shape {
private DrawStrategy drawStrategy;

public Shape(DrawStrategy drawStrategy) {
this.drawStrategy = drawStrategy;
}

public void draw() {
drawStrategy.draw();
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
Shape circle = new Shape(new CircleDrawStrategy());
Shape rectangle = new Shape(new RectangleDrawStrategy());
Shape triangle = new Shape(new TriangleDrawStrategy());

circle.draw();
rectangle.draw();
triangle.draw(); // 添加新策略不需要修改Shape
}
}

 

### 4. 使用工厂模式

工厂模式可以用于创建形状对象,从而将对象的创建与使用分离。

// 形状工厂接口
public interface ShapeFactory {
Shape createShape();
}

// 圆形工厂
public class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Shape(new CircleDrawStrategy());
}
}

// 矩形工厂
public class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Shape(new RectangleDrawStrategy());
}
}

// 三角形工厂
public class TriangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Shape(new TriangleDrawStrategy());
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
ShapeFactory rectangleFactory = new RectangleFactory();
ShapeFactory triangleFactory = new TriangleFactory();

Shape circle = circleFactory.createShape();
Shape rectangle = rectangleFactory.createShape();
Shape triangle = triangleFactory.createShape();

circle.draw();
rectangle.draw();
triangle.draw(); // 添加新形状只需新建工厂类
}
}

 

### 5. 事件驱动架构

如果我们希望在绘制形状时能够触发事件,可以使用事件驱动架构。我们可以定义一个事件监听器接口,并在绘制时触发事件。

// 事件监听器接口
public interface DrawListener {
void onDraw();
}

// 形状类
public class Shape {
private DrawStrategy drawStrategy;
private DrawListener listener;

public Shape(DrawStrategy drawStrategy, DrawListener listener) {
this.drawStrategy = drawStrategy;
this.listener = listener;
}

public void draw() {
if (listener != null) {
listener.onDraw(); // 触发事件
}
drawStrategy.draw();
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
Shape circle = new Shape(new CircleDrawStrategy(), () -> System.out.println("Circle is being drawn"));
Shape rectangle = new Shape(new RectangleDrawStrategy(), () -> System.out.println("Rectangle is being drawn"));

circle.draw();
rectangle.draw(); // 事件被触发
}
}

 

### 总结

通过深入分析开闭原则,我们可以发现它在软件设计中的重要性。遵循开闭原则可以让我们的代码更加灵活、可维护和可扩展。无论是通过接口、抽象类、策略模式还是工厂模式,或者结合事件驱动架构,我们都可以实现这一原则。

1. **灵活性**:可以轻松添加新功能,而不需要修改现有代码。
2. **降低耦合**:通过接口和抽象类,系统的各个部分相互独立。
3. **提高可维护性**:现有代码的稳定性得以保证,维护成本降低。

通过这些示例,可以看到如何在实际开发中应用开闭原则,以构建更高质量的软件系统。

更多实用教程资源

http://sj.ysok.net/jydoraemon 访问码:JYAM

标签:draw,java,示例,刨析,class,Shape,void,new,public
From: https://www.cnblogs.com/HQING/p/18606116

相关文章

  • burp(2)利用java安装burpsuite
    BurpSuite安装burpsuite2024.10专业版,已经内置java环境,可以直接使用,支持WindowslinuxmacOS!!!内置jre环境,无需安装java即可使用!!!bp2024.10下载地址:https://pan.baidu.com/s/1E2aVKnnfTWl2SL-ztR_JtQ?pwd=m5pv激活1.首先点击Start.bat2.进入,点击Copy3.点击CN_Burp......
  • 使用idea创建一个JAVA WEB项目
    文章目录1.javaweb项目简介2.创建2.1idea新建项目2.2选择,命名2.3打开2.4选择tomcat运行2.5结果3.总结1.javaweb项目简介JavaWeb项目是一种基于Java技术的Web应用程序,主要用于开发动态网页和Web服务。这种项目能够构建在Java技术栈之上,支持开发人员利用Java......
  • 2024最强Java面试八股文(精简、纯手打)
    2024最新最全国内大厂Java面试高频题库本小册内容涵盖:Java基础,JVM,多线程,数据库(MySQL/Redis)SSM,Dubbo,网络,MQ,Zookeeper,Netty,微服务,大数据,算法,项目,设计模式等,篇幅足足近2千页,大家面试前拿去提前刷刷,一、基础篇1.接口和抽象类的区别相似点:(1)接口和抽象类都不能被实例化(2)实......
  • 2025年最新完整java面试题(含答案)
    1**、面向对象的特征有哪些方面****【基础】**答:面向对象的特征主要有以下几个方面:1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一......
  • java agent 介绍
    javaagent系列javaagent介绍javaagent-02-JavaInstrumentationAPIjavaagent-03-JavaInstrumentation结合bytekit实战笔记agentattachjavaagent-03-JavaInstrumentation结合bytekit实战笔记agentpremainjava-javaagent解释在Java中,-javaagent是一种Ja......
  • Java IO模型
    JavaIO模型  一、什么是IO? I/O(Input/Output)即输入/输出。 1. 从计算机结构的角度来解读I/O 根据冯.诺依曼结构,计算机结构分为5大部分:运算器、控制器、存储器、输入设备、输出设备。如下图:  从计算机结构的视角来看的话,I/O描述了计算机系统与外部设备之......
  • JAVA毕业设计——springboot001基于SpringBoot的在线拍卖系统
    springboot001基于SpringBoot的在线拍卖系统目录springboot001基于SpringBoot的在线拍卖系统一、系统介绍二、所用技术三、环境介绍四、页面截图五、浏览地址一、系统介绍后台管理员登录包含以下功能:个人中心、用户管理、商品类型管理,拍卖商品管理、历史竞拍管理......
  • 基于java的SpringBoot/SSM+Vue+uniapp的校园新闻网站的详细设计和实现(源码+lw+部署文
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于java的SpringBoot/SSM+Vue+uniapp的新生宿舍管理系统的详细设计和实现(源码+lw+部
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 【Java】轻松解决支付宝沙箱问题。
    ......