C# 创建实例级接口的最佳方式
C# best way to create instance level interface
举个例子,假设我有一个带有一堆节点的有向无环图。我想遍历图,但是每个节点都有一个保护条件。例如,如果节点 A
的值小于 10,我只能遍历到节点 B
。因此我创建了一个名为 IsActive
的方法,该方法是针对每个节点的。我尝试使用抽象 class 方法对其进行建模:
abstract class Node
{
public int value;
public abstract bool IsActive();
}
class NodeB : Node
{
public override bool IsActive()
{
// return nodeA.value < 10
}
}
但是,我想避免为每个节点创建一个新的 class。那么在实例级别 initialise/implement 方法的最佳方法是什么?我做了一些其他的事情,但我真的不确定“最好”的方法是什么...
谢谢!
你不需要很多 class。你可以简单地使用你的 Node
class 但修改它。
public class Node
{
public int Value { get; set; } = 0;
public int LowerValueLimit { get; set; } = int.MinValue;
public int UpperValueLimit { get; set; } = int.MaxValue;
public bool IsActive()
{
return Value >= LowerValueLimit && Value <= UpperValueLimit ;
}
}
现在只需创建您的节点并在逻辑中烘焙它们
// is active will be true for anything between int.MinValue to 10
var nodeA = new Node() { UpperValueLimit = 10 };
// will be active for value between 50 and 60
var nodeB = new Node() { LowerValueLimit = 50, UpperValueLimit = 60 };
您可以将 Func<bool>
作为 属性 在您的 Node
class:
public class Node
{
public int Value {get;set;}
public Func<bool> IsActiveFunction { get; set; }
public bool IsActive()
{
return IsActiveFunction.Invoke();
}
}
这样你就可以独立定义每个节点的条件:
Node nodeA = new Node();
Node nodeB = new Node();
nodeA.IsActiveFunction = () => nodeB.Value < 10;
nodeB.IsActiveFunction = () => Math.sin(nodeA.Value) == 0; // bad example, because you should not use == to compare doubles, but you get the idea
我会更进一步,创建可用于创建验证逻辑的接口
using System;
using System.Collections.Generic;
using System.Linq;
namespace NodeExample
{
class Program
{
static void Main(string[] args)
{
var graphRoot = new Node(1);
var nodeA = new Node(7, new ValidateNodeBehaviour(currentNode => currentNode.Value >= 5));
var nodeB = new Node(3, new ValidateNodeBehaviour(currentNode => currentNode.Value >= 10 && nodeA.Value <= 10));
var nodeC = new Node(4);
graphRoot.Connections.Add(nodeA);
graphRoot.Connections.Add(nodeB);
nodeB.Connections.Add(nodeC);
//traverse the graph
var currentNode = graphRoot;
while (true)
{
var availableConnection = currentNode.Connections.FirstOrDefault(x => x.IsValid());
if (availableConnection == null)
break;
currentNode = availableConnection;
}
}
}
public interface IValidatableBehavior
{
public bool IsValid(Node currentNode);
}
public class ValidateNodeBehaviour : IValidatableBehavior
{
private Func<Node, bool> validateFunc;
public ValidateNodeBehaviour(Func<Node, bool> validateFunc)
{
this.validateFunc = validateFunc ?? throw new ArgumentNullException(nameof(validateFunc));
}
public bool IsValid(Node currentNode)
{
return validateFunc(currentNode);
}
}
public class Node
{
private readonly IValidatableBehavior validatableBehavior;
public int Value { get; set; }
public List<Node> Connections { get; } = new List<Node>();
public Node(int value)
{
Value = value;
}
public Node(int value, IValidatableBehavior validatableBehavior) : this(value)
{
this.validatableBehavior = validatableBehavior;
}
public bool IsValid()
{
if (validatableBehavior == null)
{
return true;
}
return validatableBehavior.IsValid(this);
}
}
}
举个例子,假设我有一个带有一堆节点的有向无环图。我想遍历图,但是每个节点都有一个保护条件。例如,如果节点 A
的值小于 10,我只能遍历到节点 B
。因此我创建了一个名为 IsActive
的方法,该方法是针对每个节点的。我尝试使用抽象 class 方法对其进行建模:
abstract class Node
{
public int value;
public abstract bool IsActive();
}
class NodeB : Node
{
public override bool IsActive()
{
// return nodeA.value < 10
}
}
但是,我想避免为每个节点创建一个新的 class。那么在实例级别 initialise/implement 方法的最佳方法是什么?我做了一些其他的事情,但我真的不确定“最好”的方法是什么...
谢谢!
你不需要很多 class。你可以简单地使用你的 Node
class 但修改它。
public class Node
{
public int Value { get; set; } = 0;
public int LowerValueLimit { get; set; } = int.MinValue;
public int UpperValueLimit { get; set; } = int.MaxValue;
public bool IsActive()
{
return Value >= LowerValueLimit && Value <= UpperValueLimit ;
}
}
现在只需创建您的节点并在逻辑中烘焙它们
// is active will be true for anything between int.MinValue to 10
var nodeA = new Node() { UpperValueLimit = 10 };
// will be active for value between 50 and 60
var nodeB = new Node() { LowerValueLimit = 50, UpperValueLimit = 60 };
您可以将 Func<bool>
作为 属性 在您的 Node
class:
public class Node
{
public int Value {get;set;}
public Func<bool> IsActiveFunction { get; set; }
public bool IsActive()
{
return IsActiveFunction.Invoke();
}
}
这样你就可以独立定义每个节点的条件:
Node nodeA = new Node();
Node nodeB = new Node();
nodeA.IsActiveFunction = () => nodeB.Value < 10;
nodeB.IsActiveFunction = () => Math.sin(nodeA.Value) == 0; // bad example, because you should not use == to compare doubles, but you get the idea
我会更进一步,创建可用于创建验证逻辑的接口
using System;
using System.Collections.Generic;
using System.Linq;
namespace NodeExample
{
class Program
{
static void Main(string[] args)
{
var graphRoot = new Node(1);
var nodeA = new Node(7, new ValidateNodeBehaviour(currentNode => currentNode.Value >= 5));
var nodeB = new Node(3, new ValidateNodeBehaviour(currentNode => currentNode.Value >= 10 && nodeA.Value <= 10));
var nodeC = new Node(4);
graphRoot.Connections.Add(nodeA);
graphRoot.Connections.Add(nodeB);
nodeB.Connections.Add(nodeC);
//traverse the graph
var currentNode = graphRoot;
while (true)
{
var availableConnection = currentNode.Connections.FirstOrDefault(x => x.IsValid());
if (availableConnection == null)
break;
currentNode = availableConnection;
}
}
}
public interface IValidatableBehavior
{
public bool IsValid(Node currentNode);
}
public class ValidateNodeBehaviour : IValidatableBehavior
{
private Func<Node, bool> validateFunc;
public ValidateNodeBehaviour(Func<Node, bool> validateFunc)
{
this.validateFunc = validateFunc ?? throw new ArgumentNullException(nameof(validateFunc));
}
public bool IsValid(Node currentNode)
{
return validateFunc(currentNode);
}
}
public class Node
{
private readonly IValidatableBehavior validatableBehavior;
public int Value { get; set; }
public List<Node> Connections { get; } = new List<Node>();
public Node(int value)
{
Value = value;
}
public Node(int value, IValidatableBehavior validatableBehavior) : this(value)
{
this.validatableBehavior = validatableBehavior;
}
public bool IsValid()
{
if (validatableBehavior == null)
{
return true;
}
return validatableBehavior.IsValid(this);
}
}
}