【问题标题】:Is Template Method design pattern a good choice for this?模板方法设计模式是一个不错的选择吗?
【发布时间】:2012-08-21 07:02:05
【问题描述】:

目前我有一些这样的代码:

    OntologyGenerator generator = new OntologyGenerator();
    generator.AddOntologyHeader("Testing");
    generator.AddClassDeclaration(owlBuilder);
    generator.AddSubClass(owlBuilder);
    generator.AddAnnotationAssertions(owlBuilder);

你看到的 OwlBuilder 参数在哪里有这样的对象集合:

public class OwlLBuilder: IOwlLBuilder
{
       private ICollection<IOwlClass> owlClasses = new Collection<IOwlClass>();
       private ICollection<IOwlRelation>  owlRelations = new Collection<IOwlRelation> ();
}

例如,当我说 generator.AddClassDeclaration(owlBuilder); 时,它将循环遍历该 owlBuilder 参数的 owlClasses 集合并对其执行一些操作...

我觉得这是一个丑陋的设计。您认为我可以利用修改现有代码以使用模板方法设计模式或您拥有的任何其他更好的设计建议来受益吗?加上一些代码示例,这样我就可以在脑海中大致了解我应该做什么!

【问题讨论】:

    标签: c# design-patterns


    【解决方案1】:

    我真的看不到这里的 Template Method。我看到Visitor pattern

    这是一个例子。

    假设你有一堆房子,你需要把它们都漆成黄色。现在你可以:

    var houses = ... a list of houses ...
    
    foreach (var house in houses)
    {
        house.Color = Color.Yellow;
    }
    

    但是,您可能希望将动作(在本例中为绘画)抽象为其他东西,而不是总是将房屋涂成黄色。一种解决方案是编写一个负责将房子涂成黄色的类。该课程稍后可以替换为另一个课程,该课程以不同的颜色粉刷房屋,或者对您的房屋进行完全不同的操作,例如添加另一层楼!

    输入访客模式。

    我将展示一些我一直在使用的通用帮助类和接口。我喜欢泛型。如果你不这样做,请随意滚动你自己的。语义是:“访问者访问可访问者”,以及“可访问者接受访问者”。

    public interface IVisitor<in T> where T : IVisitable<T>
    {
        void Visit(T visitable);
    }
    
    public interface IVisitable<out T> where T : IVisitable<T>
    {
        void Accept(IVisitor<T> visitor);
    }
    
    public abstract class Visitable<T> : IVisitable<T> where T : Visitable<T>
    {
        public void Accept(IVisitor<T> visitor)
        {
            visitor.Visit((T)this);
        }
    }
    
    public abstract class VisitableList<T> : List<T>, IVisitable<T> where T : Visitable<T>
    {
        public void Accept(IVisitor<T> visitor)
        {
            foreach (var item in this)
            {
                item.Accept(visitor);
            }
        }
    }
    

    现在我们可以像这样设置我们的房子和我们的房子列表:

    public class House : Visitable<House>
    {
        public Color Color { get; set; }
    }
    
    public class Houses : VisitableList<House> {}
    

    现在,访客——我们的画家——可以参观我们可参观的房子:

    public class YellowPainter : IVisitor<House>
    {
        public void Visit(House visitable)
        {
            visitable.Color = Color.Yellow;
        }
    }
    

    简单、优雅和single responsibility(!)

    让我们设置房子:

    var houses = new Houses();
    houses.Add(new House() { Color = Color.Green });
    houses.Add(new House() { Color = Color.Blue });
    houses.Add(new House() { Color = Color.White });
    

    现在我们已经准备好粉刷我们所有的房子了。只需一个电话:

    houses.Accept(new YellowPainter());
    

    ...我们所有的房子现在都是黄色的。不错!

    我们可以很容易地做到这一点:

    houses.Accept(new AdditionalFloorsBuilder(floors: 2));
    

    或者这个:

    owlClasses.Accept(new OwlClassVisitor(owlBuilder, ...));
    

    通过这样做,我们将owlClasses 中每个元素的实际“访问”与集合本身的迭代隔离开来。访问不需要修改可访问的。它可以用来只检查可访问的并使用信息来修改完全不同的东西,例如。您可以使用这些信息来提供您的owlBuilder

    【讨论】:

    • 确实如此。致 OP:与此处的策略模式有很大重叠(我个人将“YellowPainter”称为“PaintYellowStrategy”。en.wikipedia.org/wiki/Strategy_pattern
    • @ChristofferLette 同意,我的问题的真正意图是问引爆点在哪里?
    • 两种模式都支持在不修改原始源的情况下插入行为的方式。在 TM 中,原始源通常是一个抽象类,它规定了调用语义和顺序。子类与其基类紧密耦合,这意味着子类可以使用更多与基类交互的方式。
    • (续) 在 V 中,访问者是“负责人”,因此控制是倒置的。可访问对象也没有强加的语义。但是,与可访问对象的交互仅限于可访问对象接口的公共部分。上面列出的差异(我可能遗漏了一些重要的差异)可以用来调整规模,具体取决于您的需要。
    • @neontapir 看来我们达成了一致。要么我们都是对的,要么我们都错了!干杯。 ;-)
    猜你喜欢
    • 1970-01-01
    • 2016-01-14
    • 2019-08-23
    • 2010-11-02
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 2015-09-16
    相关资源
    最近更新 更多