我之前问了一个类似的问题,得到了一些很好的答案,但我觉得它太笼统了.
有没有人知道任何展示真正优秀的TDD实践和SOLID原则的开源项目?TDD和SOLID被广泛宣传,但我从未见过它自己做过,我只是想了解一个项目(大或小)的样子?
作为整体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) 最近我做了关于依赖注入和IoC(控制反转)容器的演示.我也在谈论SOLID原则.我认为没有SOLID,DI容器毫无意义.
我专注于几个论点.
然而,当科技集团回复说他们没有看到与容器进行DI等等时,我有点失望
我承认演示文稿可能并不完美,并且消息没有传达.
任何人都可以告诉我如何让观众相信依赖注入是一件好事.如何说服他们改变他们对松散耦合类和组件的看法(我们也对此进行了一些争论)
DI的"杀手"论点是什么?
我正在努力了解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) 我想重构以下代码以避免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) 我正在对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# 开发一个持久性库。在那个库中,我已经实现了存储库模式,我遇到了一个 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 的情况下解决这个问题......
在本文之后,服务聚合器模型可以应用于这种情况,因此代码看起来像这样:
持久化库中包含的抽象存储库:
public abstract class Repository<T>
{ …Run Code Online (Sandbox Code Playgroud) 这是一个非常简单的问题,我仍然非常不安:
为什么现在广泛接受类通过访问器方法返回对其私有成员的引用?这不完全打破封装原则吗?如果这样可以,那为什么不公开会员!?
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 ......
正如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) Liskov 替换原则 (LSP) 和接口隔离原则 (ISP) 之间有什么核心区别吗?最终,两者都保证设计具有通用功能的界面,并在您具有特殊功能时引入新界面。
liskov-substitution-principle interface solid-principles interface-segregation-principle
solid-principles ×10
c# ×7
asp.net ×2
oop ×2
asp.net-mvc ×1
inheritance ×1
interface ×1
interface-segregation-principle ×1
java ×1
liskov-substitution-principle ×1
open-source ×1
single-responsibility-principle ×1
tdd ×1