【问题标题】:Run time type identification运行时类型识别
【发布时间】:2015-05-18 13:54:45
【问题描述】:

我想在运行时检查类型,但我不想在 Java 中使用 instanceOf()getClass() 方法。

因此我做了以下事情:

我创建了一个枚举

public enum CarType{
            SEDAN,
            SUV
        }

我创建了一个界面

public interface Car{

public CarType getCarType();
}

然后我写了两个实现Car的类。

public class Sedan implements Car{
   public CarType getCarType(){
     return CarType.SEDAN
  }
}

现在另一个类是

public class Suv implements Car{
       public CarType getCarType(){
         return CarType.Suv
      }
}

然后我在其他类的方法中使用这些类作为

class CarUI{

    public void updateTheUIConsideringCarType(CarType type) {
            switch(type){
            case SUV:
               //UI to update when car type is SUV
            case SEDAN:
               //UI to update when car type is SEDAN
                break;
            default: 
              break;
          }
        }
}

我想问一下,如果我用这种方式是不是很好,还是和使用instanceOf()一样,我想坚持OOP。

如果有更好的方法请告诉我。

【问题讨论】:

  • 这比依赖继承稍微好一点(继承是开放式的,而枚举具有固定数量的元素)但仍然不理想。确切的解决方案将取决于许多因素。
  • 最好的方法是在Car 接口中声明updateTheUI 方法并在每个类中单独实现。我自己会认为枚举switchinstanceof 更干净,但两者都不是很好。一种可能的方法是使CarUI 成为一个接口并为每种类型实现它。
  • @Bubletan 我不同意。您建议将模型与 UI 相关活动直接耦合。但是这样的事情应该是独立的。所以你的建议是一种解决方法,但没有什么能使它成为“最好的方法”。
  • @Bubletan 这是处理它的一种方法。您还可以创建一个CarUIUpdater 接口并将单独的实现传递给每辆汽车,以避免汽车代码与UI 更新代码混合。还有很多其他选项,但问题不够详细,无法选择。
  • @Jägermeister 是的,再想一想,如果 UI 相关的东西在 Car 里面可能会有点乱。但仍将其拆分为多个类可以使其更有条理。

标签: java oop inheritance enums polymorphism


【解决方案1】:

使用这种机制当然是个好主意 - 它可以节省我们以后的许多工作。

您还可以采取进一步的步骤(如果适合您的代码) - 让 enum 进行 UI 绘制。

public interface CanDraw {

    public void draw();
}

public enum CarType implements CanDraw {

    SEDAN {

                @Override
                public void draw() {
                    // Do your UI drawing here.
                }

            },
    SUV {

                @Override
                public void draw() {
                    // Do your UI drawing here.
                }

            };
}

public void updateTheUIConsideringCarType(CarType type) {
    type.draw();
}

如 cmets 中所述,这有时会导致您的 UI 代码泄漏到模型代码中。通常最好通过从 UI 中返回功能来避免这种情况 - 如下所示:

public interface CanDraw {

    public void draw();
}

// In your UI.
public enum CarDrawingPolicy implements CanDraw {

    SMALL {

                @Override
                public void draw() {
                    // Do your UI drawing here.
                }

            },
    BIG {

                @Override
                public void draw() {
                    // Do your UI drawing here.
                }

            };
}

public interface HasDrawingPolicy {

    public CarDrawingPolicy getDrawingPolicy();
}

// In your Model
public enum CarType implements HasDrawingPolicy {

    SEDAN {

                @Override
                public CarDrawingPolicy getDrawingPolicy() {
                    return CarDrawingPolicy.SMALL;
                }

            },
    SUV {

                @Override
                public CarDrawingPolicy getDrawingPolicy() {
                    return CarDrawingPolicy.BIG;
                }

            };
}

public void updateTheUIConsideringCarType(CarType type) {
    type.getDrawingPolicy().draw();
}

【讨论】:

  • 我不确定让enum 进行绘画是个好主意。看起来您将模型与视图代码混为一谈。如果您正在编写 MVC 应用程序,则应将模型和视图的关注点分开。
  • @Jesper 在 UI 的情况下,这是有争议的,但原则上,策略枚举并没有错。如果你调用枚举 CarDrawingPolicy 而不是 CarType,这将是一个教科书式的解决方案。
  • @Jesper - 你是对的 - 让enum 做太多事情并不总是合适的,但是让enum 知道如何 去做(也许通过注射)可能是一个非常有效的中途解决方案。
【解决方案2】:

这种方法的问题在于,任何新的 Car 实现都需要对多个文件进行更改,这些文件必须彼此保持同步。换句话说,这些类是紧密耦合的。 无论 updateTheUIConsideringCarType 中的逻辑是什么,都应该封装在每个汽车实现中。

所以你的汽车界面可能是这样的:

public interface Car{
    public Object getUiStuff();
}

那么你的 updateTheUIConsideringCarType 将被定义为:

public void updateTheUIConsideringCarType(Car car) {
    car.getUiStuff();
}

【讨论】:

  • 我不同意,这是在模型中添加视图问题。例如,如果在应用程序的多个层中使用 Car,则 UI 类甚至可能不会出现在中间层或持久层的类路径中。
  • @DraganBozanovic 我不想对 Car 对象的性质做出任何假设。如果它们是模型对象,那么添加汽车视图对象就足够简单了,解决方案保持不变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多