我正在制作角色扮演游戏,只是为了好玩,并了解有关SOLID原则的更多信息.我关注的第一件事就是SRP.我有一个"角色"类,代表游戏中的角色.它有Name,Health,Mana,AbilityScores等等.
现在,通常我也会在我的Character类中放置方法,所以它看起来像这样......
public class Character
{
public string Name { get; set; }
public int Health { get; set; }
public int Mana { get; set; }
public Dictionary<AbilityScoreEnum, int>AbilityScores { get; set; }
// base attack bonus depends on character level, attribute bonuses, etc
public static void GetBaseAttackBonus();
public static int RollDamage();
public static TakeDamage(int amount);
}
Run Code Online (Sandbox Code Playgroud)
但是由于SRP,我决定将所有方法都移到一个单独的类中.我将该类命名为"CharacterActions",现在方法签名看起来像这样......
public class CharacterActions
{
public static void GetBaseAttackBonus(Character character);
public static int RollDamage(Character character);
public static TakeDamage(Character character, int amount);
} …Run Code Online (Sandbox Code Playgroud) 我正在构建一个WinForms应用程序,其UI只包含一个NotifyIcon动态填充的UI ContextMenuStrip.有一个MainForm共同持有的申请,但这是从来没有看见.
我开始尽可能安全地构建它(使用Autofac来处理对象图)并且对我的成功感到非常满意,即使使用O部分也相当不错.随着我目前正在实施的扩展,似乎我发现了我的设计中的一个缺陷,需要重新改造一下; 我想知道我需要去的方式但是有点不清楚如何准确定义依赖关系.
如上所述,菜单部分在启动应用程序后动态填充.为此,我定义了一个IToolStripPopulator接口:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
Run Code Online (Sandbox Code Playgroud)
将此实现注入到MainForm,并且Load()方法PopulateToolStrip()使用ContextMenuStrip表单中定义的处理程序调用.populator的依赖关系仅与获取用于菜单项的数据有关.
这个抽象通过一些进化步骤很好地工作,但是当我需要多个事件处理程序时,这已经不够了,例如因为我正在创建几个不同的菜单项组 - 仍然隐藏在单个IToolStripPopulator界面后面,因为表单不应该是完全关心这一点.
正如我所说,我想我知道一般结构应该是什么样的 - 我将IToolStripPopulator接口重命名为更具体的东西*并创建了一个新PopulateToolStrip()方法,其方法不接受EventHandler参数,而是将其注入到对象中(也允许更多关于实现所需的处理程序数量的更多灵活性等).这样,我的"最重要的" IToolStripPopulator可以很容易地成为任何数量的特定适配器的适配器.
现在我不清楚的是我应该如何解决EventHandler依赖项.我认为处理程序应该全部定义MainForm,因为它具有正确响应菜单事件所需的所有其他依赖项,并且它还"拥有"菜单.这意味着我IToolStripPopulator最终注入到MainForm中的MainForm对象的依赖关系需要依赖于对象本身Lazy<T>.
我的第一个想法是定义一个IClickHandlerSource接口:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
Run Code Online (Sandbox Code Playgroud)
这是由我实现的MainForm,我的具体IToolStripPopulator实现依赖于Lazy<IClickHandlerSource>.虽然这有效,但它是不灵活的.我要么必须为可能越来越多的处理程序定义单独的接口(严重违反OCP与MainForm类)或不断扩展IClickHandlerSource(主要违反ISP).直接依赖事件处理程序在消费者方面看起来是一个好主意,但是通过惰性实例(或类似)的属性单独连接构造函数似乎非常混乱 - 如果可能的话.
我最好的打赌似乎是这样的: …
c# dependency-injection inversion-of-control winforms solid-principles
我知道SOLID原则是针对面向对象语言编写的.
我在书中找到了罗伯特·马丁的"嵌入式C的测试驱动开发",本书最后一章的后续句子:
"应用开放封闭原则和Liskov替代原则可以实现更灵活的设计."
由于这是一本C(无c ++或c#)的书,应该有一种方法来实现这个原则.
在C中实现这个原则有什么标准方法吗?
Liskov 替换原则 (LSP) 和接口隔离原则 (ISP) 之间有什么核心区别吗?最终,两者都保证设计具有通用功能的界面,并在您具有特殊功能时引入新界面。
liskov-substitution-principle interface solid-principles interface-segregation-principle
罗伯特马丁说:"一个班级改变的理由永远不应该超过一个".
让我们考虑绑定到View的ViewModel类.ViewModel可能(甚至可能)由彼此不相关的属性组成.对于小视图,ViewModel可能非常一致,但是当应用程序变得更加复杂时,ViewModel将公开可能因不同和无关原因而发生变化的数据.
我们是否应该在ViewModel类的情况下担心SRP原则?
如问题所示,
由于我们使用像IsNullOrEmpty或IsNullOrWhiteSpace这样的字符串函数作为函数显示的名称,这些函数执行多个作业,是不是违反了SRP?
相反,它不应该是string.isValid(Enum typeofValidation)而不是使用策略模式来选择正确的策略进行验证.
或者在实用程序类或静态类中违反SRP是完全可以的.
language-agnostic oop single-responsibility-principle multiple-inheritance solid-principles
在我们的C#MVC应用程序中,我们有很多接口,它们将实现它们的对象映射为1到1.即:基本上,对于创建的每个对象,已经执行了"提取界面"操作.
Moq使用这些接口为我们的单元测试生成模拟对象.但这是接口重复使用的唯一时间.
我们系统中没有具体对象实现多个接口.
谁能告诉我这是否会导致问题在路上?如果是这样,他们会是什么?
我在想,我们的应用程序有很多重复,例如在这两个接口(编辑:在我们的服务层)中,唯一不同的是方法名称和它们所采用的参数类型,但在语义上他们做与他们发送消息的存储库相同:
interface ICustomer
{
void AddCustomer(Customer toAdd);
void UpdateCustomer(Customer toUpdate);
Customer GetById(int customerId);
}
interface IEmployee
{
void AddEmployee(Employee toBeAdded);
void UpdateEmployee(Employee toUpdate);
Employee GetById(int employeeId);
}
Run Code Online (Sandbox Code Playgroud)
这就是我认为重用的抽象原则会出现的地方,即将代码转换为类似的东西:
public interface IEmployee: IAdd<Employee>, IUpdate<Employee>, IFinder<Employee>
Run Code Online (Sandbox Code Playgroud)
这与存储库模式无关 - 这是关于任何层中的接口,看起来它们共享语义相同的行为.是否值得为这些操作派生通用接口并使"子接口"继承它们?
至少它会保持方法的签名一致.但这会给我带来什么其他好处呢?(除了利斯科夫替代原则)
现在,方法的名称和返回类型都到处都是.
我读过Mark Seemann关于Reused抽象原理的博客,但我不明白,坦白说.也许我只是愚蠢:)我还阅读了Fowler对Header Interfaces的定义.
例如,我们有以下结构:
class Base
{
[pure]
public virtual bool IsValid(/*you can add some parameters here*/)
{
//body
}
}
class Child : Base
{
public override bool IsValid(/*you can add some parameters here*/)
{
//body
}
}
Run Code Online (Sandbox Code Playgroud)
你能否填写Base::IsValid()并Child::IsValid()与不同的机构,但没有与LSP的冲突?让我们想象它只是分析的方法,我们无法改变实例的状态.我们能做到吗?我对任何一个例子感兴趣.在一般情况下,我试图了解虚拟(身体)布尔方法是否是反模式.
oop design-patterns liskov-substitution-principle solid-principles
我一直在阅读SOLID原则,并想知道在DOTNET中是否有一个很好的大型开源应用程序或项目,它显示了在现实世界产品中使用的SOLID原则.
如果有任何其他开源项目被认为是良好的编码样本,我也很想看到它们.
solid-principles ×10
c# ×5
oop ×3
liskov-substitution-principle ×2
single-responsibility-principle ×2
abstraction ×1
c ×1
c++ ×1
c++11 ×1
interface ×1
interface-segregation-principle ×1
mvvm ×1
open-source ×1
silverlight ×1
winforms ×1
wpf ×1