I'm new in this pattern , could please someone help me in it?
I got an Object like this :
public class Object
{
public string Name { get; set; }
public object Value { get; set; }
public List<Object> Childs { get; set; }
}
Here is an JSON example:
{
"Name": "Method",
"Value": "And",
"Childs": [{
"Name": "Method",
"Value": "And",
"Childs": [{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "5",
"Childs": []
}]
},
{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "6",
"Childs": []
}]
}]
},
{
"Name": "Operator",
"Value": "IsEqual",
"Childs": [{
"Name": "Name",
"Value": "3",
"Childs": []
}]
}]
}
My question how to make Visitor Pattern in order to get this final string:
(Name IsEqual 3)And((Name IsEqul 5)And(Name IsEqual 6))
To implement visitor pattern you need two simple interfaces
IVisitable
with an Accept
method having the IVisitor
as the parameter.IVisitor
with many Visit
methods for each implementation of IVisitable
So basic idea of the visitor pattern is to change the behavior dynamically according to the type of implementation.
For your case the thing you want to visit (the visitable) is the Object
class which apparently does not have different derivatives and you want to change the behavior according to a property value not the type. So Visitor Pattern is not what you really need here and I highly recommend you to consider the answers with the recursive method.
But if you really want to use visitor pattern here, it may look something like this.
interface IVisitable { void Accept(IVisitor visitor); }
interface IVisitor {
void VisitAnd(Object obj);
void VisitEquals(Object obj);
}
Since the Object
class is a simple POCO I assume you won't want to implement an interface and add a method into this class. So you'll need an adapter object which adapts Object
to IVisitable
class VisitableObject : IVisitable {
private Object _obj;
public VisitableObject(Object obj) { _obj = obj; }
public void Accept(IVisitor visitor) {
// These ugly if-else are sign that visitor pattern is not right for your model or you need to revise your model.
if (_obj.Name == "Method" && _obj.Value == "And") {
visitor.VisitAnd(obj);
}
else if (_obj.Name == "Method" && _obj.Value == "IsEqual") {
visitor.VisitEquals(obj);
}
else
throw new NotSupportedException();
}
}
}
public static ObjectExt {
public static IVisitable AsVisitable(this Object obj) {
return new VisitableObject(obj);
}
}
And finally the visitor implementation may look like this
class ObjectVisitor : IVisitor {
private StringBuilder sb = new StringBuilder();
public void VisitAnd(Object obj) {
sb.Append("(");
var and = "";
foreach (var child in obj.Children) {
sb.Append(and);
child.AsVisitable().Accept(this);
and = "and";
}
sb.Append(")");
}
public void VisitEquals(Object obj) {
// Assuming equal object must have exactly one child
// Which again is a sign that visitor pattern is not bla bla...
sb.Append("(")
.Append(obj.Children[0].Name);
.Append(" Equals ");
.Append(obj.Children[0].Value);
.Append(")");
}
}