”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 面向实体的开发

面向实体的开发

发布于2024-08-06
浏览:738

Desenvolvimento Orientado a SOLID

在软件开发中,代码维护、扩展和灵活性对于项目的长期成功非常重要。 SOLID 原则的制定是为了指导开发人员创建更易于理解、修改和扩展的代码。在本文中,我们将分别讨论 5 个 SOLID 原则以及如何通过 Java 中的实际示例来使用它们。

1. 单一职责原则

单一职责原则 (SRP) 规定,一个类必须只有一个更改理由,即它必须在系统内具有单一职责。

// Antes de aplicar o SRP
class ProductService {
    public void saveProduct(Product product) {
        // Lógica para salvar o produto no banco de dados
    }

    public void sendEmail(Product product) {
        // Lógica para enviar um email sobre o produto
    }
}
// Após aplicar o SRP
class ProductService {
    public void saveProduct(Product product) {
        // Lógica para salvar o produto no banco de dados
    }
}

class EmailService {
    public void sendEmail(Product product) {
        // Lógica para enviar um email sobre o produto
    }
}

在示例中,我们将在数据库中保存产品的责任与发送有关产品的电子邮件的责任分开。这有利于未来的更改,因为发送电子邮件的更改不再影响产品保存逻辑。

2. 开闭原理

开放/封闭原则(OCP)建议软件实体(类、模块、函数等)应该对扩展开放,但对修改封闭。这是通过使用抽象和继承来实现的。

// Exemplo inicial violando o OCP
class AreaCalculator {
    public double calculateArea(Rectangle[] rectangles) {
        double area = 0;
        for (Rectangle rectangle : rectangles) {
            area  = rectangle.width * rectangle.height;
        }
        return area;
    }
}
// Exemplo após aplicar o OCP
interface Forma {
    double calculateArea();
}
class Rectangle implements Forma {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public double calculateArea() {
        return width * height;
    }
}

class AreaCalculator {
    public double calculateArea(Forma [] formas) {
        double area = 0;
        for (Forma formas: formas) {
            area  = forma.calculateArea();
        }
        return area;
    }
}

在第二个示例中,最初 AreaCalculator 类直接依赖于 Rectangle 类。这意味着如果您想添加其他类型的形状,例如圆形或三角形,则需要修改 AreaCalculator 类,从而违反 OCP。通过创建 Shape 接口,AreaCalculator 类能够接收新的几何形状,而无需修改现有代码。

3.里氏替换原理

里氏替换原则(LSP)规定超类的对象必须可以被其子类的对象替换,而不影响系统的完整性。换句话说,子类的行为必须与超类的行为一致。

// Classe base
class Bird {
    public void fly() {
        // Método padrão que imprime "Flying"
        System.out.println("Flying");
    }
}

// Classe derivada que viola o LSP
class Duck extends Bird {
    @Override
    public void fly() {
        // Sobrescrita que imprime "Ducks cannot fly"
        System.out.println("Ducks cannot fly");
    }
}

问题:Duck 类重写了 Fly() 方法来打印“鸭子不能飞”,从而改变了 Bird 基类中定义的默认行为,即所有鸟都会飞(“飞行”)。这违反了 LSP,因为任何期望 Bird 对象或其子类会飞的代码都无法与 Duck 一起正常工作,而我们已经知道 Duck 不会飞。

// Classe derivada que respeita o LSP
interface Bird {
    void fly();
}
class Eagle implements Bird {
    @Override
    public void fly() {
        System.out.println("Flying like an Eagle");
    }
}
class Duck implements Bird {
    @Override
    public void fly() {
        throw new UnsupportedOperationException("Ducks cannot fly");
    }
}

通过这种方法,Eagle 和 Duck 可以在需要 Bird 的地方互换,而不会破坏 Bird 界面设定的期望。 Duck 抛出的异常显式地传达了鸭子不会飞的信息,而没有以可能导致代码中出现意外问题的方式修改超类的行为。

4. 接口隔离原则

接口隔离原则(ISP)建议类的接口应该特定于使用它们的客户端。这避免了需要实现客户端未使用的方法的“胖”接口。

// Exemplo antes de aplicar o ISP
interface Worker {
    void work();
    void eat();
    void sleep();
}

class Programmer implements Worker {
    @Override
    public void work() {
        // Lógica específica para programar
    }
    @Override
    public void eat() {
        // Lógica para comer
    }
    @Override
    public void sleep() {
        // Lógica para dormir
    }
}
// Exemplo após aplicar o ISP
interface Worker {
    void work();
}
interface Eater {
    void eat();
}
interface Sleeper {
    void sleep();
}
class Programmer implements Worker, Eater, Sleeper {
    @Override
    public void work() {
        // Lógica específica para programar
    }
    @Override
    public void eat() {
        // Lógica para comer
    }
    @Override
    public void sleep() {
        // Lógica para dormir
    }
}

在示例中,我们将 Worker 接口拆分为更小的接口(Work、Eat、Sleep),以确保实现它们的类仅具有它们需要的方法。这可以防止类必须实现与它们不相关的方法,从而提高代码的清晰度和内聚性。

5. 依赖倒置原则

依赖倒置原则(DIP)建议高层模块(例如实现主要业务规则的业务或应用程序类)不应依赖于低层模块(基础设施类,例如访问外部数据和支持高级操作的服务)。两者都必须依赖于抽象。

// Exemplo antes de aplicar o DIP
class BackendDeveloper {
    public void writeJava() {
        // Lógica para escrever em Java
    }
}
class Project {
    private BackendDeveloper developer;

    public Project() {
        this.developer = new BackendDeveloper();
    }
    public void implement() {
        developer.writeJava();
    }
}
// Exemplo após aplicar o DIP
interface Developer {
    void develop();
}
class BackendDeveloper implements Developer {
    @Override
    public void develop() {
        // Lógica para escrever em Java
    }
}
class Project {
    private Developer developer;

    public Project(Developer developer) {
        this.developer = developer;
    }
    public void implement() {
        developer.develop();
    }
}

Project 类现在依赖于抽象(Developer)而不是具体实现(BackendDeveloper)。这允许不同类型的开发人员(例如 FrontendDeveloper、MobileDeveloper)轻松注入 Project 类,而无需修改其代码。

结论

采用 SOLID 原则不仅可以提高代码质量,还可以增强您的技术技能、提高工作效率并促进您作为软件开发人员的职业道路。

版本声明 本文转载于:https://dev.to/womakerscode/desenvolvimento-orientado-a-solid-al7?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • PART# 使用 HTTP 进行大型数据集的高效文件传输系统
    PART# 使用 HTTP 进行大型数据集的高效文件传输系统
    让我们分解提供的HTML、PHP、JavaScript和CSS代码对于分块文件上传仪表板部分。 HTML 代码: 结构概述: Bootstrap for Layout:代码使用 Bootstrap 4.5.2 创建一个包含两个主要部分的响应式布局: 分块上传部分:用于...
    编程 发布于2024-11-06
  • 比较:Lithe 与其他 PHP 框架
    比较:Lithe 与其他 PHP 框架
    如果您正在为下一个项目探索 PHP 框架,很自然会遇到 Laravel、Symfony 和 Slim 等选项。但是,是什么让 Lithe 与这些更强大、更知名的框架区分开来呢?以下是一些突出 Lithe 如何脱颖而出的注意事项。 1. 轻量级和性能 Lithe 的设计重点关注轻量级架...
    编程 发布于2024-11-06
  • 编码风格指南:编写简洁代码的实用指南
    编码风格指南:编写简洁代码的实用指南
    在过去的五年里,我一直在不断尝试提高我的编码技能,其中之一就是学习和遵循最推荐的编码风格。 本指南旨在帮助您编写一致且优雅的代码,并包含一些提高代码可读性和可维护性的建议。它的灵感来自于社区中最受接受的流行指南,但进行了一些修改以更适合我的喜好。 值得一提的是,我是一名全栈 JavaScript 开...
    编程 发布于2024-11-06
  • 检查类型是否满足 Go 中的接口
    检查类型是否满足 Go 中的接口
    在Go中,开发人员经常使用接口来定义预期的行为,使代码灵活且健壮。但是如何确保类型真正实现接口,尤其是在大型代码库中? Go 提供了一种简单有效的方法来在编译时验证这一点,防止运行时错误的风险并使您的代码更加可靠和可读。 您可能见过类似的语法 var _ InterfaceName = TypeN...
    编程 发布于2024-11-06
  • 掌握 JavaScript 中的 &#this&# 关键字
    掌握 JavaScript 中的 &#this&# 关键字
    JavaScript 中的 this 关键字如果不理解的话可能会非常棘手。这是即使是经验丰富的开发人员也很难轻松掌握的事情之一,但一旦你掌握了,它可以为你节省大量时间。 在本文中,我们将了解它是什么、它在不同情况下如何工作以及使用它时不应陷入的常见错误。 在 JavaScript ...
    编程 发布于2024-11-06
  • PHP 中的用户浏览器检测可靠吗?
    PHP 中的用户浏览器检测可靠吗?
    使用 PHP 进行可靠的用户浏览器检测确定用户的浏览器对于定制 Web 体验至关重要。 PHP 提供了两种可能的方法: $_SERVER['HTTP_USER_AGENT'] 和 get_browser() 函数。$_SERVER['HTTP_USER_AGENT']...
    编程 发布于2024-11-06
  • 增强您的 Web 动画:像专业人士一样优化 requestAnimationFrame
    增强您的 Web 动画:像专业人士一样优化 requestAnimationFrame
    流畅且高性能的动画在现代 Web 应用程序中至关重要。然而,管理不当可能会使浏览器的主线程过载,导致性能不佳和动画卡顿。 requestAnimationFrame (rAF) 是一种浏览器 API,旨在将动画与显示器的刷新率同步,从而确保与 setTimeout 等替代方案相比更流畅的运动。但有效...
    编程 发布于2024-11-06
  • 为什么MySQL服务器在60秒内就消失了?
    为什么MySQL服务器在60秒内就消失了?
    MySQL 服务器已消失 - 恰好在 60 秒内在此场景中,之前成功运行的 MySQL 查询现在遇到了60 秒后超时,显示错误“MySQL 服务器已消失”。即使调整了 wait_timeout 变量,问题仍然存在。分析:超时正好发生在 60 秒,这表明是设置而不是资源限制是原因。直接从 MySQL ...
    编程 发布于2024-11-06
  • 为什么带有“display: block”和“width: auto”的按钮无法拉伸以填充其容器?
    为什么带有“display: block”和“width: auto”的按钮无法拉伸以填充其容器?
    了解具有“display: block”和“width: auto”的按钮的行为当您设置“display: block”时一个按钮,它会调整其布局以占据可用的整个宽度。但是,如果将其与“width: auto”结合使用,则按钮会出现意外行为,并且无法拉伸以填充其容器。此行为源于按钮作为替换元素的基本...
    编程 发布于2024-11-06
  • 为 Bluesky Social 创建机器人
    为 Bluesky Social 创建机器人
    How the bot will work We will develop a bot for the social network Bluesky, we will use Golang for this, this bot will monitor some hashtags ...
    编程 发布于2024-11-06
  • 为什么 PHP 的浮点运算会产生意外的结果?
    为什么 PHP 的浮点运算会产生意外的结果?
    PHP 中的浮点数计算精度:为什么它很棘手以及如何克服它在 PHP 中处理浮点数时,这一点至关重要了解其固有的准确性限制。如代码片段所示:echo("success");} else {echo("error");} 您可能会惊讶地发现,尽管值之间的差异小于 ...
    编程 发布于2024-11-06
  • Python中可以通过变量ID逆向获取对象吗?
    Python中可以通过变量ID逆向获取对象吗?
    从 Python 中的变量 ID 检索对象引用Python 中的 id() 函数返回对象的唯一标识。人们很容易想知道是否可以反转此过程并从其 ID 获取对象。具体来说,我们想要检查取消引用变量的 ID 是否会检索原始对象:dereference(id(a)) == a理解解引用的概念及其在 Pyth...
    编程 发布于2024-11-06
  • Go 的 Defer 关键字如何在函数执行顺序中发挥作用?
    Go 的 Defer 关键字如何在函数执行顺序中发挥作用?
    了解 Go 的 Defer 关键字的功能使用 Go 时,了解 defer 关键字的行为至关重要。该关键字允许开发人员推迟函数的执行,直到周围的函数返回。但是,需要注意的是,函数的值和参数在执行 defer 语句时进行评估。示例:评估 Defer Order为了说明这一点,请考虑以下内容代码:pack...
    编程 发布于2024-11-06
  • WordPress Gutenberg 全局状态管理初学者指南
    WordPress Gutenberg 全局状态管理初学者指南
    构建复杂的 WordPress 块编辑器 (Gutenberg) 应用程序时,有效管理状态变得至关重要。这就是 @wordpress/data 发挥作用的地方。它允许您跨 WordPress 应用程序中的不同块和组件管理和共享全局状态。 如果您不熟悉管理全局状态或使用@wordpress/data,...
    编程 发布于2024-11-06
  • 亚马逊解析简单且完全由您自己完成
    亚马逊解析简单且完全由您自己完成
    I came across a script on the Internet that allows you to parse product cards from Amazon. And I just needed a solution to a problem like that. I wrac...
    编程 发布于2024-11-06

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3