我试图第一次坚持罗伯特·马丁的SOLID设计原则,我并不擅长。
本质上,我需要一个“Node”对象的层次结构。一些节点是NodeHosts,一些是NodeChildren,一些是Both。以前每个人都做过这个,但我无法弄清楚如何在没有过度复杂的设计或在节点子类型中做这样的事情的情况下实现它:
INodeHostType node;
public INodeType NodeType
{
....
set
{
node = (INodeHostType)value;
}
}
这违反了Liskov Substitution Principle吗?什么是更好的方式? 这就是我现在拥有的。
答案 0 :(得分:4)
男人这个答案确实增长了,但很有趣。我们走了:))
我同意这是一个非常复杂的设计。当您使用接口来“抽象变化的东西”时,接口很有用,但在该示例中,所有内容都是抽象的。这个例子真的很难遵循,所以这应该是一个错误的重要指标。 Spaghetti Code的反面是Lasagna Code(很多层),这就是这个图的确切含义。
从我可以看到你有3组。
让我们从节点开始,它确实是SOLID告诉你对接口进行编码,但这并不一定意味着它必须是一个实际的接口。使用常规旧继承和扩展basenode的子节点是完全可以接受的。在这种情况下,这仍然是可靠的。
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
对于渲染,现在你正在做点什么。由于ChildNodes和ParentNodes的呈现方式不同,因此抽象它是有意义的。虽然,我看到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
}