标签: solid-principles

瘦和胖接口之间的"细线"是什么?

我有一个预订系统,允许您预订,修改现有预订和取消现有预订.我正在研究接口隔离原理,我想知道我应该如何轻松地创建我的接口,如果我违反了单一责任原则.我的初始设计是:

interface IReservation
{
     void Book();
     void Modify();
     void Cancel(); 
}
Run Code Online (Sandbox Code Playgroud)

但后来我想,如果一个预约系统,不需要为预约实现这些方法之一,并且只关注预订,那么我做了以下事情:

interface IBook
{
     void Book();
}


interface IModify
{
    void Modify();
}

interface ICancel
{
    void Cancel();
}
Run Code Online (Sandbox Code Playgroud)

现在我可以这样做:

interface IReservation : IBooking
{


}
Run Code Online (Sandbox Code Playgroud)

要么

interface IReservation : IBooking, IModify
{


}
Run Code Online (Sandbox Code Playgroud)

所以问题就变成了我把它变得如此稀疏.此外,更难以考虑接口的名称,例如,我不喜欢IModify或ICancel(它们看起来像我应该在IReservation接口上的方法).你如何确定接口应该进入什么以及应该将哪些内容转移到另一个接口,类等等......

.net oop interface solid-principles

4
推荐指数
1
解决办法
373
查看次数

SQLAlchemy:知道模型对象的字段名称和值吗?

我正在努力保持面向对象的 SOLID 编程原则,保持 DRY 等,但我对 Python/SQLAlchemy/Pyramid 的陌生使它变得非常困难。

我正在尝试采用我现在知道的用于创建简单 Pyramid Framework 对象的 SQLAlchemy 模型,并使用我所知道的 C# 中的“反射”,它可能在 Python 中被称为不同的东西(内省?不确定,因为这只是我使用 python 的第二周,但我在其他语言(C/C++/C#、Java 等)方面有很多经验,所以麻烦似乎是将我的知识映射到 python 的词汇表,抱歉),以找出数据库表的字段名,最重要的是当前字段值,当我事先不知道列名或任何形状的对象时。

这是正确的; 我不知道 'derp' 实例有一个名为 id 或 name 的字段,只是它在每个字段中都有一个列和一个值。这就是我所关心的。

目标是能够采用任何 SQLAlchemy 定义的数据模型,并将其转换为 column_name -> column_value 字段的字典,这些字段的类型为 JSON 中的简单数据类型,因为我想最终将我在 SQLAlchemy 中创建的任何对象序列化为json 对象,但我会选择一个字典,因为只要字典包含正确类型的数据,它就很简单。手动为每个对象执行此操作违反了太多良好的干净代码规则,并且随着时间的推移会产生过多的工作;我可以再花一个星期的时间来做这件事,并且仍然可以通过正确的方式来节省时间和精力。

因此,如果我在 SQLAlchemy 中定义了一个类:

class SimpleFooModel(Base):
    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    name = Column(VARCHAR(length=12), nullable=False, index=True)
Run Code Online (Sandbox Code Playgroud)

..我有一个等于(在python中)的实例:

derp = SimpleFooModel(id=7, name="Foobar")
Run Code Online (Sandbox Code Playgroud)

我希望能够只拥有上面描述的“derp”实例变量,而对模型的形状一无所知,并且能够将其展平为该简单对象的 python 键-> 值字典,其中每个可以使用 python syslib 中的 import json 将该字典中的值序列化为 JSON。

问题是,我已经看了 2 天了,但找不到可以在任何地方为我的单元测试提供想要的结果的答案;谷歌一直把我带到 SO 上关于真正旧版本的库的非常旧的帖子,这些版本要么使用不再适用的接口,要么接受了实际上根本不起作用的答案;并且因为它们都不是最近的,这确实让我感到惊讶(但是为什么 Stack …

python json sqlalchemy solid-principles pyramid

4
推荐指数
1
解决办法
2035
查看次数

解释这个关于依赖倒置原则的励志海报

这篇博文中,这个励志海报描述了依赖倒置原则:

海报

我不明白海报的意思:将灯直接焊接到墙上如何违反依赖倒置原则以及插头如何遵循依赖倒置原则。也许一些关于灯和电源插座的骨架 Java 或 C# 代码可能会有所帮助。

oop dependencies solid-principles dependency-inversion

4
推荐指数
1
解决办法
568
查看次数

liskov 替换原则违反

我在学习liskov substitution principle。它说sub classes should be proper replacement for the base classes

我读了一个例子,我在互联网的不同地方找到了这个例子。一类Rectangle.javaheight, width他们setter and getter methods。一个Square.java只需要一个属性的类,即length. 如果我们有,Square.java extending Rectangle.java那么这违反了这一原则。这是因为Rectangle.java期望的用户width只要height修改就不会受到影响,反之亦然。

我的疑惑:

  1. 我们看到的情况是,方法只是用空的打开和关闭大括号覆盖,以防止执行在基类中编写的默认代码。这种情况是否违反了这一原则?

  2. 这个原则也说不inheritance应该仅仅用于重用代码。在下面的情况下,这是一种不好的做法,这是否违反了这一原则?

如果类 Window.java 可从某个图形库获得。假设它具有绘制窗口所需的所有代码。还假设它在使用和绘制时有一个工具栏。如果要求是创建一个没有工具栏的窗口。

简单地创建一个 WindowWithoutToolBar.java 扩展 Window.java 并覆盖 drawToolBarMethod() 并将其留空就可以解决目的。 [可能只是创建工具栏而不是绘制它,以避免其他方法尝试访问工具栏时发生任何异常object] 这是一种不好的做法吗?

创建一个没有工具栏的全新 Window 类将需要重写所有已经在 Window.java 中编写的代码。

  1. 对于数字,如果我们有一个 Integer.java 类,其中包含用于各种算术运算的代码,这些算术运算可以使用整数进行平方等。如果我们以后需要 NaturalNumber.java,我们可以轻松地从现有的 Integer 扩展它。 java 并添加检查以仅将正整数作为输入。

现在如果我们需要 AbsoluteNumber.java 那么如果我们从 Integer.java 扩展它,这是否违反了这个原则(如果 Integer.java 有一些方法如 getValueAfterMultiplyByNegativeOne())? …

oop liskov-substitution-principle solid-principles

4
推荐指数
1
解决办法
2393
查看次数

“对扩展开放,对修改封闭”的原则有意义吗?

在我看来,Bob Martin 需要一些以 O 开头的东西来制作 SOLID,并在一些旧书中找到了这个(可能没用的)开/闭原则。

开放/封闭如何与单一职责共存,即一个类应该有一个改变的原因?

如果我想在一个长期存在的系统中遵循 Open/Closed,我是否应该有几十个/几百个类的链,每个类都扩展前一个?

oop design-patterns open-closed-principle solid-principles

4
推荐指数
2
解决办法
2504
查看次数

为什么单例违反开放/封闭原则?

谁能告诉我为什么单例违反开/关原则?是因为从该类继承可能存在问题吗?

singleton design-patterns solid-principles

4
推荐指数
3
解决办法
2136
查看次数

没有代码重复的单一职责原则(怎么办?)

我向在软件架构领域拥有先进知识的人们提出这个问题。我试图理解与消除代码冗余的想法相关的单一职责原则(SOLID)的想法。我对代码重复的看法是,代码重复是需要修复和消除的错误。实际上,我正在阅读 \xe2\x80\x9cClean Architecture\xe2\x80\x9d (Robert C. Martin),我的看法发生了变化,我有点困惑。

\n\n

SRP 强调参与者,因此 Robert Martin 写道 \xe2\x80\x9cA 模块应该对一个且仅一个参与者负责,即参与者\xe2\x80\x9d。作为一个例子,R. Martin 谈到了两个类(模块)。第一个类包含会计部门指定的方法\xe2\x80\x9ccalculatedPay()\xe2\x80\x9d。另一个类包含由另一个参与者(人力资源部门)指定的方法 \xe2\x80\x9creportHours()\xe2\x80\x9d 。这两个函数共享共同的算法(例如小时计算)。自然的方法是将通用算法移至另一个类并消除代码重复。之后,两个函数都会调用新类中的算法。想象一下会计部门需要更改算法(在新类中)。更改后,人力资源部门使用新的(无效)算法。存在问题,并且该问题是由于破坏 SRP 造成的。算法类(模块)对两个参与者负责。另一方面,我们会有不必要的代码重复,这让我焦躁不安。

\n\n

也许我关于代码重复的教条方法是错误的,在许多地方使用相同的代码并没有什么错。不是吗?如果我从不同的角度来看它,那么我会看到有多种算法/或者只是多个客户端(参与者)使用的代码部分。有时需要更改所使用的代码。这对我来说是很自然的事情。另一种方式是什么?这就是为什么我不太明白为什么不将重复项放入另一个类中的原因。另一个不同观点的例子,两个类各有一个函数,共享共同的算法,但都由会计部门指定。没有 SRP 中断,因为只有一个参与者仍然存在相同的问题,因为一个更改可能会使另一个类失效。这在某种程度上非常不准确......

\n\n

也许我不了解 SRP 及其背后的想法...

\n

architecture design-patterns coding-style solid-principles clean-architecture

4
推荐指数
1
解决办法
1634
查看次数

如何将路径配置从另一个服务注入到ServeStaticModule中?

NestJS 文档说要像这样提供静态文件:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'client'),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

但作为一名 DI 和 SOLID 从业者,我想让 rootPath 可配置。可以说我有一个ConfigModule或我自己的ConstantsModule。我如何rootPath以类似的方式注入?

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: this.configService.get<string>('staticRootPath'),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class …
Run Code Online (Sandbox Code Playgroud)

dependency-injection solid-principles nestjs nestjs-config

4
推荐指数
1
解决办法
1609
查看次数

尝试理解里氏替换原理

我试图理解里氏替换原则,我有以下代码:

class Vehicle {
}

class VehicleWithDoors extends Vehicle {
    public void openDoor () {
        System.out.println("Doors opened.");
    }
}

class Car extends VehicleWithDoors {
}

class Scooter extends Vehicle {
}

class Liskov {
    public static void function(VehicleWithDoors vehicle) {
        vehicle.openDoor();
    }

    public static void main(String[] args) {
        Car car = new Car();
        function(car);
        Scooter scooter = new Scooter();
        //function(scooter);  --> compile error
    }
}

Run Code Online (Sandbox Code Playgroud)

我不确定这是否违反。原则上说,如果你有一个类 S 的对象,那么你可以用类 T 的另一个对象替换它,其中 S 是 T 的子类。但是,如果我写怎么办

Vehicle vehicle = new …
Run Code Online (Sandbox Code Playgroud)

java solid-principles

4
推荐指数
1
解决办法
2507
查看次数

复杂流程的单一责任原则

当我必须保证的过程相当复杂时,我总是有一个问题,如何保证单一责任原则。

我使用 3 层架构后端:控制器(我的 API 端点)| 服务(单一职责功能)| 数据(访问数据库)

假设我有一个由 4 个任务, , ,ProcessA组成的流程。TasksA1TasksA2TasksA3TasksA4

如果我的控制器层上公开了一个端点,例如:POSTMethodProcessA

应该如何编写我的代码以尊重我的服务层的单一责任原则?

我看到的选项:

选项1(控制器必须知道该过程):

class MyController {
  exports.processA = functions.https.onRequest(req, res) => {
    myservice.doTaskA1(); // single responsability on task1
    myservice.doTaskA2(); // single responsability on task1
    myservice.doTaskA3(); // single responsability on task1
    myservice.doTaskA4(); // single responsability on task1
  });
}

Run Code Online (Sandbox Code Playgroud)

选项 2(服务了解流程并放弃单一责任)

class MyController {
  exports.processA = functions.https.onRequest(req, res) => {
    myservice.doProcessA();
  });
}

//inside the service (the doProcessA …
Run Code Online (Sandbox Code Playgroud)

architecture design-patterns single-responsibility-principle solid-principles

4
推荐指数
1
解决办法
357
查看次数