SOLID 时代,我最幸运

2025-06-07

SOLID 时代,我最幸运

程序的目标是不是坚固?我不担心,但我想说明一下我们的例子,但我们并没有对此进行深入研究。

什么是 SOLID?

作为面向对象的程序,从 设计的角度来看, SOLID 一词 为了  帮助理解、开发和制造软件。

我们结合原则,不减少错误的产生,提高编码的质量,组织编码的生产,减少附件,改善编码并重新评估编码。

S - Princípio da responsabilidade única

责任原则范例

SRP——单一职责原则

阶级发展的本质、意义、动机

这是所有的功能和责任的变数。 Provavelmente você já fez ou se deparou com alguma classe que faz de tudo um pouco, a tal da God Class .这是一个非常重要的时刻,需要解决逻辑问题并解决问题。

God Class - Classe Deus: 一个面向对象的程序,是一个可以使用的类或常用的类。

class Task {
    createTask(){/*...*/}
    updateTask(){/*...*/}
    deleteTask(){/*...*/}

    showAllTasks(){/*...*/}

    existsTask(){/*...*/}

    TaskCompleter(){/*...*/}
}
Enter fullscreen mode Exit fullscreen mode

该类任务是SRP的基本任务,是四个不同的任务。该任务可用于执行、显示、验证和验证任务

问题是这样的:

  • Falta de nexo- uma classe não deve Assumir responsabilidades que não são suas;
  • Muita informação junta- sua classe vai ficar com muitas dependentências e uma grande diificuldade para alterações;
  • Dificuldades na implementação de testes automatizados- “mockar”的困难是 经典的;

Agora 应用SRP任务,其原理如下:

class TaskHandler{ 
    createTask() {/*...*/} 
    updateTask() {/*...*/} 
    deleteTask() {/*...*/} 
} 

class TaskViewer{ 
    showAllTasks() {/*...*/} 
} 

class TaskChecker { 
    existsTask() {/*...*/} 
} 

class TaskCompleter { 
    completeTask() {/*...*/} 
}
Enter fullscreen mode Exit fullscreen mode

Daria 可以创建、更新和删除各个类,它们依赖于上下文和项目以及所需的复杂性。

如果您不这样做,请按照以下方法和功能进行相反的操作só vou conseguir aplicar isso em classes?

//❌
function emailClients(clients: IClient[]) {

    clients.forEach((client)=>{
        const clientRecord = db.find(client);

        if(clientRecord){
            sendEmail(client);
        }
    })
}

//✅
function isClientActive(client: IClient):boolean { 
    const clientRecord = db.find(client); 
    return !!clientRecord; 
}

function getActiveClients(clients: IClient[]):<IClient | undefined> { 
    return clients.filter(isClientActive); 
}

function emailClients(clients: IClient[]):void { 
    const activeClients = getActiveClients(clients);
    activeClients?.forEach(sandEmail); 
}
Enter fullscreen mode Exit fullscreen mode

Código mais bonito,优雅和组织。基本原理是作为结尾的基础,因此您可以轻松地使用它来获得资格,轻松地休闲和轻松地进行操作。

O - 开放日期原则

Princípio Aberto-Fechado 的例子

OCP-开放封闭原则

对象或实体的原则是扩展、修改、必要的附加功能和功能,并且不能更改字体。

想象一下,在学校秘书处的小系统中,存在两个班级,代表着学生的一个等级,基本的和中等的。 Além de uma classe que é para definir as aulas do aluno。

class EnsinoFundamental {
    gradeCurricularFundamental(){}
}

class EnsinoMedio {
    gradeCurricularMedio(){}
}

class SecretariaEscola {
    aulasDoAluno: string; 

    cadastrarAula(aulasAluno){
        if(aulasAluno instanceof EnsinoFundamental){
            this.aulasDoAluno = aulasAluno.gradeCurricularFundamental();
        } else if(aulasAluno.ensino instanceof EnsinoMedio){
            this.aulasDoAluno = aulasAluno.gradeCurricularMedio();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

一个类SecretariaEscola的响应验证是否有足够的能力以将其应用到地籍中。 Agora 想象一下,如果你对技术和技术有很高的要求,那么在没有系统的情况下,你需要对课程进行修改,然后就可以了,所以你会遇到一些问题,或者是小提琴或坚固Princípio Aberto-Fechado东西

有什么解决办法吗? Provavelmente adicionar um else ifna classe e pronto,问题已解决。 Não pequeno Padawan 😐,这是问题!

在新的辅助工具中,我们将介绍一些新的错误,并介绍一些新的功能。

Lembre-se: OCP 可以提供更改和扩展的权限。

Veja a beleza que fica ao refatorar o código:

interface gradeCurricular {
    gradeDeAulas();
}

class EnsinoFundamental implements gradeCurricular {
    gradeDeAulas(){}
}

class EnsinoMedio implements gradeCurricular {
    gradeDeAulas(){}
}

class EnsinoTecnico implements gradeCurricular {
    gradeDeAulas(){}
}

class SecretariaEscola {
    aulasDoAluno: string;

    cadastrarAula(aulasAluno: gradeCurricular) {
        this.aulasDoAluno = aulasAluno.gradeDeAulas();
    }
}
Enter fullscreen mode Exit fullscreen mode

必须遵循地籍和光环的查SecretariaEscola马尔方法。如果您想了解地籍的等级,请注意以下事项: 观察所需的辅助工具或所需的材料或材料EnsinoTecnico

这是为了实现一个接口gradeCurricular

将接口的扩展性与依赖项的相反性分开。

鲍勃叔叔

  • Aberto para extensão: 可以使用额外的阿尔古玛新功能或与经典的标准字体相匹配。
  • Fechado para modificação:该类功能或组合不存在问题算法,不改变新算法的源代码。

L - 里氏替换原理

里氏替换原理示例

LSP - 里氏替换原则

里氏替换原理——由类基派生  的替换原理

里斯科夫在 1987 年的一次会议上介绍了他的基本原理,该会议的内容非常复杂,但我们并不担心,因此您将无法详细了解该内容,并且可以作为一个示例。

Se para cada object o1 do tito Sha um object o2 do tito T de forma que, para todos osprogramas P definidos em termos de T, o comportamento de Pé inalterado quando o1 é substituído por o2 então S éum subtipo de T

恩滕德乌? Não né, eu também não entendi na primeira vez que li isso (nem nas outras dez vezes), mas calma aí, Existe outra explicação:

如果是 T 的替代项,则 T 的对象是程序的一部分,因此可以将 T 的对象替换为程序的属性。 —— 维基百科

视觉上的平静示例如下:

class Fulano {
    falarNome() {
        return "sou fulano!";
    }
}

class Sicrano extends Fulano {
    falarNome() {
        return "sou sicrano!";
    }
}

const a = new Fulano();
const b = new Sicrano();

function imprimirNome(msg: string) {
    console.log(msg);
}

imprimirNome(a.falarNome()); // sou fulano!
imprimirNome(b.falarNome()); // sou sicrano!

Enter fullscreen mode Exit fullscreen mode

一个类 ea 类 derivada estão passando como paraâmetro eo código continua funcionando da forma esperada, magica?这就是 Liskov 的原则。

暴力行为的例子:

  • Sobrescrever/implementar um método que não faz nada;
  • Lançar uma exceção inesperada;
  • Retornar valores de tipos differente da classe base;

I - 接口隔离原理

接口隔离原理示例<br>

ISP——接口隔离原则

接口隔离原理 — 开发类的目的 是为了实现接口和不使用的方法。

接口的基本原则是通用接口的具体特征。

没有例子可以说明 criado uma 接口Animal与抽象的动画组合以及作为类实现 essa 接口的接口,veja:

interface Animal {
    comer();
    dormir();
    voar();
}

class Pato implements Animal{
    comer(){/*faz algo*/};
    dormir(){/*faz algo*/};
    voar(){/*faz algo*/};
}

class Peixe implements Animal{
    comer(){/*faz algo*/};
    dormir(){/*faz algo*/};

    voar(){/*faz algo*/};
    // Esta implementação não faz sentido para um peixe 
    // ela viola o Princípio da Segregação da Interface
}
Enter fullscreen mode Exit fullscreen mode

Animal这是一个通用接口,可与 ISPLSPPeixe原理相结合

使用ISP解决以下问题:

interface Animal {
    comer();
    dormir();
}

interface AnimalQueVoa extends Animal {
    voar();
}

class Peixe implements Animal{
    comer(){/*faz algo*/};
    dormir(){/*faz algo*/};
}

class Pato implements AnimalQueVoa {
    comer(){/*faz algo*/};
    dormir(){/*faz algo*/};
    voar(){/*faz algo*/};
}
Enter fullscreen mode Exit fullscreen mode

Agora ficou melhor、foi retirado 或 método voar()da 界面Animal和 adicionamos em uma 界面 derivada AnimalQueVoa。 Com isso o comportamento 隔离管理相关的上下文和接口隔离原则。

D - 依赖关系倒置原理

依赖倒置原理示例

DIP — 依赖倒置原则

依赖关系反转原理 — 抽象与实现的依赖关系。

  1. 中音模块不依赖于下层模块的开发。 Ambos devem依赖于抽象。

  2. 摘要不依赖于详细信息。详细信息取决于抽象。

  • 鲍勃叔叔

没有任何例子可以说明DIP 的简单情况。例如,我们可以使用不同的通知系统,例如电子邮件和短信。主要通知内容如下:

class EmailNotification {
  send(message) {
    console.log(`Enviando e-mail: ${message}`);
  }
}

class SMSNotification {
  send(message) {
    console.log(`Enviando SMS: ${message}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

Agora,vamos criar uma classe de serviço que dependente dessas 实施具体:

class NotificationService {
  constructor() {
    this.emailNotification = new EmailNotification();
    this.smsNotification = new SMSNotification();
  }

  sendNotifications(message) {
    this.emailNotification.send(message);
    this.smsNotification.send(message);
  }
}
Enter fullscreen mode Exit fullscreen mode

没有任何例子,NotificationService依赖于具体实施的EmailNotification方向SMSNotification。 Isso viola o DIP, pois a classe de alto nível NotificationServiceestá ditamente dependente de baixo nível.

Vamos corrigir esse código usando DIP。它们依赖于具体的实现,NotificationService是一个抽象的类。 Vamos criar uma 界面Notification摘要:

// Abstração para o envio de notificações
interface Notification { 
    send(message: string): void
}
Enter fullscreen mode Exit fullscreen mode

Agora,作为具体实现EmailNotificationSMSNotification开发实现 essa 接口:

class EmailNotification implements Notification {
  send(message: string) {
    console.log(`Enviando e-mail: ${message}`);
  }
}

class SMSNotification implements Notification {
  send(message: string) {
    console.log(`Enviando SMS: ${message}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,通知服务类别依赖于抽象Notification

class NotificationService {

private notificationMethod: Notification;

  constructor(notificationMethod: Notification) {
    this.notificationMethod = notificationMethod;
  }

  sendNotification(message: string) {
    this.notificationMethod.send(message);
  }
}
Enter fullscreen mode Exit fullscreen mode

这种形式NotificationService是一种抽象的依赖服务Notification类别,它不是具体的实施,而是依赖于逆向原则的实现

结论

遵循这些原则,我们的系统可以提供弹性的运动、便利的操作和良好的品质以及长时间的节奏。

所有内容均以以下方式进行:原则。能力是推动研究进展的力量。

文章来源:https://dev.to/clintonrocha98/era-solid-o-que-me-faltava-bhp
PREV
极简 Python:重温 Lambda 表达式、装饰器和其他魔法函数 什么是函数式编程? 递归 嵌套函数 闭包 Lambda 表达式 装饰器 回顾
NEXT
现代 Rails 闪现消息(第一部分):ViewComponent、Stimulus 和 Tailwind CSS