我试图遵循接口隔离和单一职责原则,但是我对如何将它们整合在一起感到困惑。
在这里,我有一个示例,其中有一些接口,我已将其拆分为更小、更直接的接口:
public interface IDataRead
{
TModel Get<TModel>(int id);
}
public interface IDataWrite
{
void Save<TModel>(TModel model);
}
public interface IDataDelete
{
void Delete<TModel>(int id);
void Delete<TModel>(TModel model);
}
Run Code Online (Sandbox Code Playgroud)
我稍微简化了它(有一些where条款妨碍了可读性)。
目前我正在使用SQLite ,但是,这种模式的美妙之处在于,如果我选择不同的数据存储方法(例如Azure),它有望让我有机会更好地适应变化。
现在,我对每个接口都有一个实现,下面是每个接口的简化示例:
public class DataDeleterSQLite : IDataDelete
{
SQLiteConnection _Connection;
public DataDeleterSQLite(SQLiteConnection connection) { ... }
public void Delete<TModel>(TModel model) { ... }
}
...
public class DataReaderSQLite : IDataRead
{
SQLiteConnection _Connection;
public DataReaderSQLite(SQLiteConnection connection) { ... }
public …Run Code Online (Sandbox Code Playgroud) c# interface single-responsibility-principle solid-principles interface-segregation-principle
我尝试遵循SOLID原则.但每次涉及到用户界面时,我发现在客户需要的笨重的混合数据集合数据和单一责任的优秀原则之间存在固有的摩擦.
现在,它是可能的分而治之的各个位和一个典型的用户界面为单责任类的作品,但后来你遇到了各种有趣的结构问题,因为贵的所谓"独立"片实际上往往变成是相同共享状态的不同视图,或者是重叠状态的至少部分视图.
我经常最终将相当笨重的控制器类混合在一起,因为我的视图并不像SOLID那样,但它的编码实践相当不一致,而且让我感到困扰.看起来分裂的复杂性似乎不值得.
那你怎么处理它?
假设我们正在设计一个执行CRUD(创建,读取,更新和删除)操作的UserServiceImpl类.在我看来,创建,读取,更新和删除是改变类的四个原因.这个类是否违反了单一责任原则?如果违反,那么,我们应该有四个类,如CreateUserServiceImpl,ReadUserServiceImpl,
UpdateUserServiceImpl,和DeleteUserServiceImpl.拥有很多课程不是一种矫枉过正的行为吗?
假设我为创建,读取,更新和删除操作定义了4个接口,我的服务类实现了所有这四个接口.现在我只能有一个实现类,但是通过分离它们的接口,就应用程序的其余部分而言,我已经解耦了这些概念.这是正确的方式还是你看到了一些问题?
我一直在阅读单元测试,TDD和SOLID原理,我需要一些澄清.我的理解是,如果遵循开放/封闭原则,单元测试可能在很大程度上变得不必要,因为代码无法修改 - 因此,如果代码被正确隔离和解耦,则无需重新测试.如果一旦代码通过相关的单元测试就不会改变单元测试所增加的前期成本的长期好处.代码将永远通过,因为它永远不会改变,对吧?需要测试继承的类,但是一旦它们通过相关的测试,它们也将被关闭以进行修改,并且不需要重新测试.关于OCP的维基百科文章强化了第一段中的这一思路(我意识到这并不能成为法律).
我发现在OCP和谐和TDD生活最好的解释是在这里,但它似乎是嫩说,OCP恭维TDD中,开发商从修改源代码的沮丧,因为修改,以测试新的时,现有的测试方法会变得复杂功能.
这就是它的全部吗?请注意,我不是在寻找一个论点,我是新手,我正在寻找那些对这个主题有更多经验的人的澄清.
最近我学习了SOLID开发,现在我遇到了一些挑战,当它是一个好的练习时,什么时候不是.
例如,我开发了一个包含成员的网站.我构建了一个Authentication Business Logic类,它可以解决身份验证方案,它们是:
这个类有4个依赖项:
现在感觉有些代码有难闻的气味,因为没有使用依赖注入.
我不确定的一些问题:
我觉得我做错了什么,请帮忙!
.net architecture asp.net-mvc dependency-injection solid-principles
目前代码契约不允许派生类中成员的前提条件,其中成员已经在基类中设置了前提条件(我实际上当前得到警告而不是错误).我不明白这背后的逻辑.我理解它与Liskov的替换规则有关,声明派生类应始终能够在父预期的地方使用.当然"使用"意味着按预期工作.对于接口而言,这对我来说似乎没问题,因为实现接口的不同类型不会添加状态,因此可以完全强制合同.但是,当您从基类继承时,您正在这样做以添加状态和特殊功能,并且通常情况下,覆盖方法会有额外的要求.为什么不能像前置条件和对象不变量一样将前置条件与AND组合在一起?
看看下面:
class Speaker
{
public bool IsPlugged { get; set; }
protected virtual void Beep()
{
Contract.Requires(IsPlugged);
Console.WriteLine("Beep");
}
}
class WirelessSpeaker : Speaker
{
public bool TransmitterIsOn { get; set; }
protected override void Beep()
{
Contract.Requires(TransmitterIsOn);
base.Beep();
}
}
Run Code Online (Sandbox Code Playgroud)
你可能会争辩说这个类层次结构打破了Liskov的规则,因为当传递给期望a的方法时,无线扬声器可能无法发出蜂鸣声Speaker.但这不是我们使用代码合同的原因吗?确保满足要求?
.net c# liskov-substitution-principle code-contracts solid-principles
如果我希望我的代码遵循SOLID原则,特别是依赖性反转原则,这是否意味着我必须为每个模块创建一个接口(抽象),即使它只有一个实现?
在我看来,并根据这些帖子:
http://josdejong.com/blog/2015/01/06/code-reuse/
http://blog.ploeh.dk/2010/12/02/Interfacesarenotabstractions/
为每个模块创建"抽象"是代码混乱并违反了YAGNI原则.
我的经验法则是:不要使用依赖注入,或者为模块创建接口,除非它有多个实现(第二个实现可以是用于数据库/服务器/文件模块的单元测试的模拟类).
有人可以为我清楚这一点吗?SOLID是否意味着我必须注入每个模块并对其进行抽象?如果是的话,是不是只是在很多时候我们根本不会使用它?
architecture dependency-injection solid-principles dependency-inversion
场景:我在类字段中存储了一些信息(例如,双精度数组)(比如字段Measurements,类中的整数数组MeasureData).现在我想使用这些数据来执行一些计算(例如,计算数组的算术平均值,最大值和最小值).此刻,我不知道在未来,我需要做的这些数据的任何其它操作(例如,也许我会需要得到标准差,总和或其他).我会有很多类型的对象MeasureData.
解决方案:我可以编写一个类Calculator,声明它是final,使用私有构造函数并使用几个静态方法来执行我需要的计算.这似乎是有道理的,因为它Calculator充当实用类,没有任何字段,就像标准Math类一样.
问题:如果在几个月内我需要进行任何其他计算,我将需要编写另一个静态方法Calculator.这是否意味着违反开放/封闭原则(毕竟,我正在修改类的实现Calculator)?
今天我工作的另一位工程师问我“这是什么责任?” 我的回答如下:
“您的代码的每个范围,无论是if语句,函数,类还是模块,都应该有一个更改的理由”。
但是,在我读到的所有这篇文章中,人们都是在课堂上谈论的。我告诉他SRP适用于他的代码中的每个范围,我错了吗?
不久前,我遇到了类似的话题。我正在看我的应用程序,我认为它有很多不必要的代码。我的意思是,我拥有负责从两个书店中的不同类别的书中抓取数据的服务。现在我有5个类别,所以我有5个方法,但是如果我要添加一些新类别呢?我将不得不添加更多方法...,我认为这不是一个好选择。现在看起来像这样:
控制者
@GetMapping("/romances")
public Map<Bookstore, List<Book>> get15RomanticBooks() {
return categorizedBookService.get15BooksFromRomanceCategory();
}
@GetMapping("/biographies")
public Map<Bookstore, List<Book>> get15BiographiesBooks() {
return categorizedBookService.get15BooksFromBiographiesCategory();
}
@GetMapping("/guides")
public Map<Bookstore, List<Book>> get15GuidesBooks() {
return categorizedBookService.get15BooksFromGuidesCategory();
}
@GetMapping("/fantasy")
public Map<Bookstore, List<Book>> get15FantasyBooks() {
return categorizedBookService.get15BooksFromFantasyCategory();
}
Run Code Online (Sandbox Code Playgroud)
在这里我在想
@GetMapping("/{category}")
public Map<......> get 15BooksFromCategory(@PathVariable CategoryType category)
{...}
Run Code Online (Sandbox Code Playgroud)
我认为这是最好的方法,但是使用服务很难。
服务如下:
package bookstore.scraper.book.scrapingtypeservice;
import bookstore.scraper.enums.Bookstore;
import bookstore.scraper.book.Book;
import bookstore.scraper.fetcher.empik.EmpikFetchingBookService;
import bookstore.scraper.fetcher.merlin.MerlinFetchingBookService;
import bookstore.scraper.urlproperties.EmpikUrlProperties;
import bookstore.scraper.urlproperties.MerlinUrlProperties;
import bookstore.scraper.utilities.JSoupConnector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public …Run Code Online (Sandbox Code Playgroud) solid-principles ×10
oop ×4
single-responsibility-principle ×3
.net ×2
architecture ×2
c# ×2
java ×2
asp.net-mvc ×1
dry ×1
interface ×1
interface-segregation-principle ×1
liskov-substitution-principle ×1
tdd ×1
unit-testing ×1