我第一次尝试坚持 Robert Martin 的 SOLID 设计原则,但我并不擅长。
本质上,我需要一个“Node”对象的层次结构。有些节点是 NodeHost,有些是 NodeChildren,有些是 Both。每个人以前都做过这个,但我不知道如何在不使设计过度复杂化或在节点子类型中执行类似操作的情况下可靠地完成它:
INodeHostType node;
public INodeType NodeType
{
....
set
{
node = (INodeHostType)value;
}
}
这违反了里氏替换原则,对吧?有什么更好的办法呢? 这就是我现在所拥有的。
最佳答案
伙计,这个答案确实很丰富,但很有趣。我们开始吧:)
我同意这是一个相当复杂的设计。当您使用接口(interface)来“抽象变化的内容”时,接口(interface)会很有帮助,但在该示例中,所有内容都是抽象的。这个例子确实很难遵循,所以这应该是一个重要的指标,表明出现了问题。与 Spaghetti 代码相反的是 Lasagna 代码(多层),这正是该图的内容。
据我所知,您有 3 个组。
- 节点(子节点、父节点等)
- 节点类型
- 渲染
让我们从节点开始,SOLID 确实告诉您为接口(interface)编写代码,但这并不一定意味着它必须是一个实际的接口(interface)。将常规旧继承与扩展基节点的子节点一起使用是完全可以接受的。这仍然是可靠的,并且在这种情况下是有意义的。
public class Node
{
public var NodeType { get; set; }
public var DisplayText { get; set; }
public IRenderable Renderer { get; set; }
public Node()
{
// TODO: Add constructor logic here
}
public void Render()
{
Renderer.Render();
}
}
public class ChildNode : Node
{
public var Owner {get; set;}
public var Sequence {get; set;}
public ChildNode()
{
NodeType = "Child"; //use an enum
DisplayText = "nom nom nom babies";
Renderer = new ChildRenderer();
}
}
//Parent Node is more of the same
对于节点类型,节点确实具有不同的类型,但它们仍然具有类型。我认为这不足以使其成为单独的抽象。我刚刚将类型移动到您的基节点中。
//This didn't add value so its just an enum used in the baseclass now
对于渲染,现在您正在做一些事情。由于 ChildNode 和 ParentNode 的渲染方式不同,因此对其进行抽象是有意义的。不过,我发现 IRenderer 中的所有属性都在 IRenderContext 中重复,因此我只是将它们折叠为 1。
interface IRenderable
{
//properties
// TODO: Add properties here
//methods
void Render();
}
interface ChildRenderer : IRenderable
{
void Render()
{
//Render Me Here
}
}
//ParentRender() is more of the same
//I could add all sorts of functionallity with out touching other code
// ManChildRenderer(), TripletsChildRenderer()
类图看起来像这样。
好吧,这一切都很好,但是为什么需要所有额外的工作呢?让我们看看最终的实现。
public static void main()
{
//if this isnt acceptle instantiation use a NodeFactory
Node node1 = new ParentNode();
Node node2 = new ChildNode();
//Now we don't care about type -- Liskov Substitution Principle
node1.Render();
node2.Render();
//adding or changing functionality is now non-breaking
node1.Renderer = new ManChildRender();
//I've added a whole new way to render confident I didnt break the old renders
//In fact I didn't even upon those class files
}
关于.net - 需要 .Net SOLID 设计方面的帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3504792/