【问题标题】:What design patterns can be used to architecture this? [closed]可以使用哪些设计模式来构建它? [关闭]
【发布时间】:2019-11-22 21:25:30
【问题描述】:

我有一个无法单独解决的架构问题。

  • 我有一系列对象实现了相同的接口 (IThing)。
  • 我想对“ITing”集合的每个对象应用转换。
  • 转换取决于接口的实现。
  • 接口实现的转换被封装在一个类中。 (策略模式)

我的问题是,在某个地方,我总是以开关类型或一组 if-is-cast 结束,对我而言,它破坏了我的代码的可扩展性。

这是一个例子:

    public interface IThing
{
    string CommonProperty { get; }
}

public class FirstThing : IThing
{
    public string CommonProperty { get; }
    public string FirstParticularProperty { get; }
}

public class SecondThing : IThing
{
    public string CommonProperty { get; }
    public string SecondParticularProperty { get; }
}

public interface IThingTransformStrategy<T> where T : IThing
{
    string Transform(T thing);
}

public class FirstThingTransformStrategy : IThingTransformStrategy<FirstThing>
{
    public string Transform(FirstThing thing)
    {
        return thing.CommonProperty + thing.FirstParticularProperty;
    }
}

public class SecondThingTransformStrategy : IThingTransformStrategy<SecondThing>
{
    public string Transform(SecondThing thing)
    {
        return thing.CommonProperty + thing.SecondParticularProperty;
    }
}

public class ThingTransformer
{
    private FirstThingTransformStrategy _firstThingTransformStrategy = new FirstThingTransformStrategy();
    private SecondThingTransformStrategy _secondThingTransformStrategy = new SecondThingTransformStrategy();

    public string TransformThing(IThing thing)
    {
        //Here is the issue
        if (thing is FirstThing) return _firstThingTransformStrategy.Transform((FirstThing) thing);
        if (thing is SecondThing) return _secondThingTransformStrategy.Transform((SecondThing) thing);
        throw new NotImplementedException();
    }
}

您有什么想法或任何模式名称来解决我的问题吗?

非常感谢。

【问题讨论】:

    标签: c# design-patterns architecture


    【解决方案1】:

    假设您无法修改每个 IThing 以知道如何转换自己,我会使用访问者模式。

    public class ThingTransformer
    {
        public string Transform(FirstThing thing) => _firstThingTransformStrategy.Transform(thing);
        public string Transform(SecondThing thing) => _secondThingTransformStrategy.Transform(thing);
    }
    
    public interface IThing
    {
        // ...
        string Transform(ThingTransformer transformer);
    }
    
    public class FirstThing : IThing
    {
        // ...
        public string Transform(ThingTransformer transformer) => transformer.Transform(this);
    }
    
    public class SecondThing : IThing
    {
        // ...
        public string Transform(ThingTransformer transformer) => transformer.Transform(this);
    }
    

    然后你可以写:

    var thing = new FirstThing();
    var transformer = new ThingTransformer();
    var transformed = thing.Transform(transform);
    

    这具有编译时安全性的优点:如果您添加 IThing 的新实现,最终会出现编译器错误,直到您将新方法添加到 ThingTransformer

    如果您想稍微抽象一点,请将ThingTransformer 隐藏在接口后面,并让IThing 使用该接口而不是具体的ThingTransformer


    更一般地,你可以写一个通用的访问者:

    public interface IThingVisitor<T>
    {
        T Accept(FirstThing thing);
        T Accept(SecondThing thing);
    }
    
    public interface IThing
    {
        T Visit<T>(IThingVisitor<T> visitor);
    }
    
    public class FirstThing : IThing
    {
        public T Visit<T>(IThingVisitor<T> visitor) => visitor.Accept(this);
    }
    
    public class SecondThing : IThing
    {
        public T Visit<T>(IThingVisitor<T> visitor) => visitor.Accept(this);
    }
    
    public class ThingTransformer : IThingVisitor<string>
    {
        public string Accept(FirstThing thing) => _firstThingTransformStrategy.Transform(thing);
        public string Accept(SecondThing thing) => _secondThingTransformStrategy.Transform(thing);
    }
    

    然后:

    var thing = new FirstThing();
    var transformer = new ThingTransformer();
    var transformed = thing.Visit(transformer);
    

    【讨论】:

    • 您好,感谢您的关注。我不希望事物知道如何转换自己,以免每次我有新的转换时都修改它们(将它放在外面允许转换策略的备用配置)。您将访客模式带到桌面上的答案很有趣,我读过它,但我仍然犹豫不决。假设一个新的请求是让转换返回 Int,然后是十进制或其他东西,我每次都必须修改我的 IThing 实现以添加一个新的 Accept 方法吗?似乎给我的模型带来了很多变化。你怎么看?
    • @Vasilievski 查看我的编辑,关于一般访问者。
    • 有趣!我尝试了这个实现,然后我回来找你!
    【解决方案2】:

    为什么要使用 ThingTransformer?

    public interface IThing
    {
        string CommonProperty { get; }
        string Transform();
    }
    
    public class FirstThing : IThing
    {
        public string CommonProperty { get; }
        public string Transform() => this.CommonProperty + this.FirstParticularProperty;
    
        public string FirstParticularProperty { get; }
    }
    
    public class SecondThing : IThing
    {
        public string CommonProperty { get; }
        public string Transform() => this.CommonProperty + this.SecondParticularProperty;
    
        public string SecondParticularProperty { get; }
    }
    

    【讨论】:

    • 嗨,我避免这样做是因为 SRP。转换事物的方式不得与事物的实现挂钩。假设 Thing 是一辆汽车,而变换是一种颜色变化,汽车本身不必知道如何改变它的颜色。
    【解决方案3】:

    恕我直言,每个 IThing 都应该知道如何转换自己。为什么不在构造 IThing 时注入正确类型的 IThingTransormStrategy?

    【讨论】:

      猜你喜欢
      • 2014-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-09
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多