【问题标题】:How to create a tree-hierarchical structure with unique behavior for every type combination?如何为每种类型组合创建具有独特行为的树层次结构?
【发布时间】:2019-02-23 22:04:53
【问题描述】:

假设:

  1. 有些模块的接口是IA
  2. 有一些模块B,它接受IA 实例的参数,其行为取决于IA 的类型,

含义(伪代码,没有特定语言,[即使我使用 Python])

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        if(type(this.ia)==A1){
             print("A1");
        }
        if(type(this.ia)==A2){
             print("A2");
        }
    }
}

我意识到我可以将一些公共方法foo 添加到ia,因此代码将简化为

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        this.ia.foo();
    }
}

我的问题有两个:

  1. 如果我(出于某种原因)无法更改IA,实现此目的的正确设计是什么,也就是说,我无法添加foo()

  2. 如果我被允许更改IA,那么正确(可扩展)的设计是什么,但现在A1A2 等重复出现同样的问题,意思是

最终期望的行为是

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        if(type(this.ia)==A1){
             if(type(this.ia.iz)==Z1){
                 print("A1Z1");
                 print("unique treatment");
             }
             if(type(this.ia.iz)==Z2){
                 print("A1Z2");
                 print("special treatment");
             }
        }
        if(type(this.ia)==A2){
             if(type(this.ia.iz)==Z1){
                 print("Z1A2");
                 print("one of a kind treatment");
             }
             if(type(this.ia.iz)==Z2){
                 print("Z2A2");
                 print("Wow treatment");
             }
        }
    }
}

并且可以重复更多次。

请注意 A1 和 A2 的 Z1 和 Z1 相同!。同样的,IZ 可以包含多种类型的IX,具有独特的行为

我想知道案例 2 是否完全独立于模块化,从某种意义上说,每个类型组合的行为都是唯一的,没有任何行为可以真正提取到更抽象的级别。

我还是不喜欢类型检查,不知道有没有可以做的更好看的东西。

【问题讨论】:

    标签: oop design-patterns


    【解决方案1】:

    您可能想查看访问者模式 (https://en.wikipedia.org/wiki/Visitor_pattern)。这确实假设您可以更改 IA 和朋友来实现 accept 方法

    【讨论】:

      【解决方案2】:

      我认为您正在寻找的是Tagged Union Types。也可以考虑Do union types actually exist in python?

      一些例子可能是 Kotlin 的 Sealed Classes and When Statement。或 Scala 的Case Classes and Sealed Traits

      如果您使用的是 Java,使用 Paguro 进行设置会有点冗长。

      interface Wheeled { }
      
      class Beetle implements Wheeled { }
      
      class Truck implements Wheeled { }
      
      // Makes a union class.
      static class Beetle_Truck extends OneOf2<Beetle,Truck> {
          private Beetle_Truck(Object o, int n) {
              super(o, Beetle.class, Truck.class, n);
          }
      
          static Beetle_Truck ofBeetle(Beetle b) {
              return new Beetle_Truck(b, 0);
          }
          static Beetle_Truck ofTruck(Truck t) {
              return new Beetle_Truck(t, 1);
          }
      }
      
      // Here's where we use it.
      @Test public void testBeetleTruck() {
          Beetle_Truck bt1 = Beetle_Truck.ofBeetle(new Beetle());
          Beetle_Truck bt2 = Beetle_Truck.ofTruck(new Truck());
      
          assertEquals("b", bt1.match(beetle -> "b",
                                      truck -> "t"));
      
          assertEquals("t", bt2.match(beetle -> "b",
                                      truck -> "t"));
      }
      

      请注意,Beetle 和 Truck 根本不需要实现通用接口。对于第二个问题,您可以只做一个类似于 OneOf2 的 OneOf4。

      【讨论】:

      • 谢谢!实际上,我主要使用 Python。我正在寻找一个不依赖于特定语言,而是依赖于 OOP 原则的答案。关于使用联合类的解决方案 - 在我看来,这只是将相同的问题转移到另一个地方。为什么这是可扩展的?含义 - 如果我现在添加另一个 A3 和另一个 Z3 会怎样?更糟糕的是 - 如果现在树有 5 层深怎么办?然后我会有Beetle_Truck_Player_Glass_Notebook extends OneOf32。我弄错了吗?
      • 如果我理解正确,您只是想做一些不同的事情,具体取决于对象的类型。而且你不想做if (myObj is TypeA) then ... else if (myObj is TypeB) then... match 语句的要点是它在编译时确保覆盖所有可能的类型。 Python 没有内置此功能,但其他一些语言有。我认为“标记的联合类型”是您的答案。
      猜你喜欢
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多