标签: solid-principles

展示TDD和SOLID原理的开源项目

我之前问了一个类似的问题,得到了一些很好的答案,但我觉得它太笼统了.

伟大的软件设计和实现的例子

有没有人知道任何展示真正优秀的TDD实践和SOLID原则的开源项目?TDD和SOLID被广泛宣传,但我从未见过它自己做过,我只是想了解一个项目(大或小)的样子?

tdd open-source solid-principles

16
推荐指数
2
解决办法
2945
查看次数

工厂应该设置模型属性吗?

作为整体SOLID编程工作的一部分,我在基础框架API中创建了工厂接口和抽象工厂.

人们已经开始重载工厂的Create方法.问题是人们正在使用模型属性重载Create方法(从而期望工厂填充它们).

在我看来,不应该由工厂进行财产设置.我错了吗?

public interface IFactory
{
    I Create<C, I>();
    I Create<C, I>(long id); //<--- I feel doing this is incorrect

    IFactoryTransformer Transformer { get; }
    IFactoryDataAccessor DataAccessor { get; }
    IFactoryValidator Validator { get; }
}
Run Code Online (Sandbox Code Playgroud)

更新 - 对于那些不熟悉SOLID原则的人,以下是其中一些原则:

单一责任原则
它规定每个对象应该只有一个责任,并且该责任应该由类完全封装

开放/封闭原则
这个原则的含义是当获得对需要添加到应用程序的功能的请求时,您应该能够在不修改旧类的情况下处理它,只需添加子类和新实现.

依赖倒置原则
它说你应该解耦你的软件模块.要实现这一点,您需要隔离依赖项.

总的来说:
我90%肯定我知道答案.但是,我想与已经使用SOLID的人进行一些很好的讨论.感谢您的宝贵意见.

更新 - 那么我认为SOLID工厂应该怎么做?

恕我直言SOLID工厂提供适当的对象实例......但这样做的方式隐藏了对象实例化的复杂性.例如,如果您有一个员工模型......您会要求工厂为您提供合适的模型.DataAccessorFactory将为您提供正确的数据访问对象,ValidatorFactory将为您提供正确的验证对象等.

例如:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();
var dataAccessorLdap = Factory.DataAccessor.Create<LDAP, IEmployee>();
var dataAccessorSqlServer = Factory.DataAccessor.Create<SqlServer, IEmployee>();
var validator = Factory.Validator.Create<ExxonMobilEmployee, IEmployee>();
Run Code Online (Sandbox Code Playgroud)

再举一个例子,我们会......

var audit …
Run Code Online (Sandbox Code Playgroud)

c# asp.net solid-principles

16
推荐指数
1
解决办法
1509
查看次数

编写SOLID应用程序最有力的理由是什么?

最近我做了关于依赖注入和IoC(控制反转)容器的演示.我也在谈论SOLID原则.我认为没有SOLID,DI容器毫无意义.

我专注于几个论点.

  1. 可维护性
  2. 可扩展性
  3. 可测性

然而,当科技集团回复说他们没有看到与容器进行DI等等时,我有点失望

我承认演示文稿可能并不完美,并且消息没有传达.

任何人都可以告诉我如何让观众相信依赖注入是一件好事.如何说服他们改变他们对松散耦合类和组件的看法(我们也对此进行了一些争论)

DI的"杀手"论点是什么?

c# dependency-injection ioc-container solid-principles

16
推荐指数
0
解决办法
3212
查看次数

了解使用单一责任原则的实际好处

我正在努力了解SRP,但是,虽然我理解了如何应用它的原因,但我并没有真正看到这样做的好处.考虑这个例子,取自Robert Martin的SRP PDF:

interface IModem
{
    void Dial(string number);
    void Hangup();
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

他建议将其分为两个界面:

interface IModemConnection
{
    void Dial(string number);
    void Hangup();
}

interface IModemDataExchange
{
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

我也一直在阅读这篇文章,它更进了一步:

interface IModemConnection : IDisposable
{
    IModemDataExchange Dial(string number);
}

interface IModemDataExchange
{
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

在这一点上,我理解functional(Send / Recv)和non-functional(Dial / Hangup)方面的含义,但我没有看到在这个例子中分离它们的好处.考虑到这个基本实现:

class ConcreteModem : IModemConnection
{
    public IModemDataExchange Dial(string number)
    {
        if (connection …
Run Code Online (Sandbox Code Playgroud)

c# single-responsibility-principle solid-principles

15
推荐指数
1
解决办法
2493
查看次数

避免如果其他条件

我想重构以下代码以避免if ... else以便每次进入新的调查类型时都不必更改方法(开放/封闭原则).以下是我正在考虑重构的一段代码:

if (surveyType == SurveySubType.Anonymous)
{
    DoSomething(param1, param2, param3);

}
else if (surveyType == SurveySubType.Invitational)
{
    DoSomething(param1);
}
else if (surveyType == SurveySubType.ReturnLater)
{    
    DoSomething(param1);
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我添加了以下类:

    public abstract class BaseSurvey
{
            public string BuildSurveyTitle()
            {
             ...doing something here
            }

    public abstract void DoSomething(int? param1,int?  param2,int?  param3);
}
public class InvitationalSurvey: BaseSurvey
{
    public override void DoSomething(int? param1,int?  param2,int?  param3)
    {
    //I don't need param2 and param3 here

    }
}


public class ReturnLaterSurvey: BaseSurvey
{
    public override void …
Run Code Online (Sandbox Code Playgroud)

c# oop open-closed-principle solid-principles

15
推荐指数
2
解决办法
2307
查看次数

存储库模式是否遵循SOLID原则?

我正在对SOLID主体进行一些研究,并在Repository模式的实现中发现了一些问题.我将解释每一个问题,如果我错了,请纠正我.

问题1

存储库模式中断单一责任原则(S)

假设我们有一个定义为的接口

public interface IRepository<T> where T: IEntity
{ 
    IEnumerable<T> List { get; }
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    T FindById(int Id);
}
Run Code Online (Sandbox Code Playgroud)

显然它违反了单一责任原则,因为当我们实现这个接口时,在一个类中,我们将命令和查询都放在一起.这不是预期的.

问题2

存储库模式中断接口隔离原则(I)

假设我们有2个以上接口的实现.

第一次实施

CustomerRepository : IRepository<Customer>
{
   //All Implementation
}
Run Code Online (Sandbox Code Playgroud)

第二次实施

ProductRepository : IRepository<Product>
{
   //All Implementation except Delete Method. So Delete Method Will be
   void Delete (Product product){
       throw Not Implement Exception!
   }
}
Run Code Online (Sandbox Code Playgroud)

并且根据ISP"没有客户应该被迫依赖它不使用的方法." 所以我们看到它显然也违反了ISP.

所以,我的理解是Repository模式不遵循SOLID主体.你怎么看?我们为什么要选择这种违反校长的模式呢?需要你的意见.

c# asp.net asp.net-mvc design-patterns solid-principles

15
推荐指数
3
解决办法
3818
查看次数

如何在 C# 中使用带有继承的依赖注入

介绍

大家好,我目前正在使用 C# 开发一个持久性库。在那个库中,我已经实现了存储库模式,我遇到了一个 SOLID 问题。这是我当前实现的一个简化示例,重点关注基本要素:

持久化库中包含的抽象存储库:

public abstract class Repository<T> 
{
    protected Repository(
        IServiceA serviceA,
        IServiceB serviceB) 
    {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

库用户创建的具体存储库:

public class FooRepository : Repository<Foo> 
{
    protected FooRepository(
        IServiceA serviceA,
        IServiceB serviceB) :
        base(serviceA, serviceB)
    {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

好的,使用当前代码,派生类必须知道基类的每个依赖项都可以,但是如果我向基类添加依赖项怎么办?每个派生类都会中断,因为它们需要将新的依赖项传递给基类......所以目前,我被限制永远不会改变基类构造函数,这是一个问题,因为我希望我的基类有可能发展。这个实现显然打破了开放/封闭原则,但我不知道如何在不打破 SOLID 的情况下解决这个问题......

要求

  • 该库应该易于用户使用
  • 具体的存储库应该能够通过 DI 构建
  • 应将一个或多个依赖项添加到抽象存储库中,而不会影响派生存储库
  • 应该可以像使用控制器的ASP.NET MVC 框架一样使用命名约定在 DI 容器中注册每个存储库
  • 如果他愿意,用户应该能够在他的派生存储库中添加更多依赖项

已经设想的解决方案

1. 服务聚合模式

本文之后,服务聚合器模型可以应用于这种情况,因此代码看起来像这样:

持久化库中包含的抽象存储库:

public abstract class Repository<T> 
{ …
Run Code Online (Sandbox Code Playgroud)

c# inheritance dependency-injection solid-principles

15
推荐指数
2
解决办法
1万
查看次数

一种非常常见的C#模式,打破了一个非常基本的OOP原则

这是一个非常简单的问题,我仍然非常不安:

为什么现在广泛接受类通过访问器方法返回对其私有成员的引用?这不完全打破封装原则吗?如果这样可以,那为什么不公开会员!?

public class EncapsulationViolator
{
  private object abuseMe;

  public object AbuseMe 
  {
    get { return abuseMe; }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑我正在考虑的案例就是这个

EncapsulationViolator ev = new EncapsulationViolator();

object o = ev.AbuseMe;

o.SetValue(newValue);
Run Code Online (Sandbox Code Playgroud)

现在,ev的状态已经通过传递性而发生变化,因为其成员滥用状态已发生变化.

在DDD的上下文中,如果对象是聚合根,则不行.我引用

允许外部对象仅保留对根的引用.可以传递对内部成员的瞬时引用,以便仅在单个操作中使用.因为根控制访问权限,所以不能通过对内部的更改来愚蠢.

[ 领域驱动设计,Eric Evans]

... setters schmetters ......

c# oop encapsulation design-principles solid-principles

14
推荐指数
3
解决办法
2008
查看次数

清除代码以删除开关条件(使用多态)

正如SOLID原则所说,最好通过将切换条件转换为类和接口来删除它们.我想用这段代码做:

注意:这段代码不是真正的代码,我只想把它放进去.

MessageModel message = getMessageFromAnAPI();
manageMessage(message);
...
void manageMessage(MessageModel message){        
    switch(message.typeId) {
        case 1: justSave(message); break;
        case 2: notifyAll(message); break;
        case 3: notify(message); break;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想删除switch语句.所以我为它创建了一些类,我尝试在这里实现一个多态:

interface Message{
    void manageMessage(MessageModel message);
}
class StorableMessage implements Message{

    @Override
    public void manageMessage(MessageModel message) {
        justSave(message);
    }
}
class PublicMessage implements Message{

    @Override
    public void manageMessage(MessageModel message) {
        notifyAll(message);
    }
}
class PrivateMessage implements Message{

    @Override
    public void manageMessage(MessageModel message) {
        notify(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我调用我的API来获取我的MessageModel:

MessageModel message = getMessageFromAnAPI(); …
Run Code Online (Sandbox Code Playgroud)

java open-closed-principle solid-principles

14
推荐指数
3
解决办法
4495
查看次数

liskov替换原理与界面隔离原理的区别

Liskov 替换原则 (LSP) 和接口隔离原则 (ISP) 之间有什么核心区别吗?最终,两者都保证设计具有通用功能的界面,并在您具有特殊功能时引入新界面。

liskov-substitution-principle interface solid-principles interface-segregation-principle

13
推荐指数
3
解决办法
3951
查看次数