我有这种表格结构:
public class Table : IVisitable
{
public List<Row> rows;
public void accept(IVisitor visitor)
{
foreach(Row row in rows)
row.accept(visitor);
visitor.visit(this);
}
}
public class Row : IVisitable
{
public List<Cell> columns;
public void accept(IVisitor visitor)
{
foreach(Cell cell in columns)
cell.accept(visitor);
visitor.visit(this);
}
}
public class Cell : IVisitable
{
public void accept(IVisitor visitor)
{visitor.visit(this);}
}
Parser会创建这个类的对象,所以我对扩展类或类似的东西有点牵强(但我可以在良好的解决方案之前重新考虑)。< / p>
现在,您可以看到我实施的accept()
方法访问整个表格,但现在我想定义一个只访问表格前两行的访问者。如果不添加另一个accept()
,我怎么能这样做?
更新 我想到了这个解决方案,我想得到你的意见。如果不重写上面的整个代码,只需想象每个类都不实现IVisitable接口(因此每个类都没有accept())。那么创建两个扩展Table的类呢?像这样:
public class VisitTwoRowTable : Table,IVisitable
{
public VisitTwoRowTable(Table table)
{
foreach(Row row in table.rows)
this.rows.add(row);
}
public void accept(IVisitor visitor)
{
for(int i=0;i<2;i++)
row[i].accept(visitor);
visitor.visit(this);
}
}
另一个:
public class VisitWholeTable : Table,IVisitable
{
public VisitWholeTable(Table table)
{
foreach(Row row in table.rows)
this.rows.add(row);
}
public void accept(IVisitor visitor)
{
foreach(Row row in rows)
row.accept(visitor);
visitor.visit(this);
}
}
此解决方案唯一的真正的UGLY 是构造函数部分,它创建一个副本(浅拷贝)
答案 0 :(得分:2)
您只需向访问者添加状态,并跟踪已访问过的行数。
鉴于这些类型(为简洁起见,我省略了Cell):
public interface IVisitor
{
void visit(Row v);
void visit(Table v);
}
public interface IVisitable
{
void accept(IVisitor visitor);
}
public class Table : IVisitable
{
public List<Row> rows;
public void accept(IVisitor visitor)
{
foreach(Row row in rows)
row.accept(visitor);
visitor.visit(this);
}
}
public class Row : IVisitable
{
public int number;
public void accept(IVisitor visitor)
{
visitor.visit(this);
}
}
您的访问者可能会像:
public class FirstTwoRowVisitor : IVisitor
{
int _numOfRows = 0;
public void visit(Row r)
{
if (_numOfRows == 2)
return;
Console.WriteLine("Visited Row #{0}", r.number);
_numOfRows++;
}
public void visit(Table t)
{
Console.WriteLine("Table has {0} Rows total", t.rows.Count);
}
}
示例:强>
var t = new Table() { rows = new List<Row>() };
int i = 0;
t.rows.Add(new Row() {number = i++});
t.rows.Add(new Row() {number = i++});
t.rows.Add(new Row() {number = i++});
t.rows.Add(new Row() {number = i++});
var v = new FirstTwoRowVisitor();
t.accept(v);
将输出
Visited Row #0
Visited Row #1
Table has 4 Rows total
(这当然只是一个简单的例子,每个实例只能处理两行;但你可以根据需要改变它)
回复您的评论:
public interface IVisitor
{
void visit(Row v);
void visit(Table v);
bool keepgoing { get; }
}
public class Table : IVisitable
{
public List<Row> rows;
public void accept(IVisitor visitor)
{
foreach(Row row in rows)
if (visitor.keepgoing) row.accept(visitor);
else break;
visitor.visit(this);
}
}
public class FirstTwoRowVisitor : IVisitor
{
int _numOfRows = 0;
public bool keepgoing { get { return _numOfRows < 2; } }
public void visit(Row r)
{
if (!keepgoing)
return;
Console.WriteLine("Visited Row #{0}", r.number);
_numOfRows++;
}
public void visit(Table t)
{
Console.WriteLine("Table has {0} Rows total", t.rows.Count);
}
}
答案 1 :(得分:1)
你可以移动
foreach (Row row in rows)
row.accept(visitor);
进入visitor.Visit(table)
方法
然后在不同的访问者中提供不同的实现,例如将您的新访问者更改为
foreach (Row row in rows.Take(2))
row.accept(visitor);
(您还必须在Table类上公开行。)