在数据处理期间避免使用类型转换

时间:2015-05-23 19:43:42

标签: java oop inheritance casting

我似乎无法找出解决以下问题的最佳方法。假设有一个带有几个具体子类的抽象基类:

public abstract class AbstractType { /* common properties */ }

public class TypeA { /* properties of type A */ }
public class TypeB { /* properties of type A */ }`

这些是域类(JPA实体)。这些类型的属性(以及其他内容)用于验证用户数据。我假设为域模型本身添加逻辑被认为是不好的做法。因此,我想避免向具体子类添加validate方法。像这样:

UserInput userInput = ...;
AbstractType data = ...;
data.validate(userInput);

我没有看到一个选项而不必投射域模型, 如果我想将逻辑移动到逻辑层。由于我的知识有限,我只能使用某种处理程序接口提出以下两个类似的“解决方案”。

  1. 对类型

    中的处理程序保留一些明确的引用
    public interface TypeHandler {
        public validate(AbstractType data, UserInput userInput);
    }
    
    /* TypeAHandler & TypeBHandler implementations */
    
    public enum Type {
        TYPE_A(new TypeAHandler()),
        TYPE_B(new TypeBHandler());
    
        private TypeHandler handler;
    
        public Handler(TypeHandler handler){
            this.handler = handler;
        }
    
        public TypeHandler getHandler(){ return handler; }
    }
    
    public class TypeA {
        private Type type = TYPE_A;
        /* ... */
    }
    

    将以下列方式调用处理程序:

    UserInput userInput = ...;
    AbstractType data = ...;
    data.getType.getHandler().validate(data, userInput);
    

    对处理程序的引用也可以立即添加(中间没有enum)作为AbstractType类的属性,但这意味着对逻辑层内的类有引用来自领域模型(哪种方式违背了将逻辑层移动到逻辑层的目的?)

    此处的问题还在于,TypeXHandler中的validate方法需要先将data参数强制转换为其子类,然后才能开始验证。

  2. 或者我可以实现一些具有大型if-then结构的方法来获取正确的子类,转换它并调用适当的处理程序来实现类似于以下的接口。

    public interface TypeHandler<T extends AbstractType> {
        public validate(T data, UserInput userInput);
    }
    
  3. 所以在这两种情况下都有铸造。在第一种情况下,没有巨大的if-then结构,但逻辑和域不是分开的。在第二种情况下,if-then结构非常不灵活。

    总而言之,这是我的问题。我真的应该避免直接在域内实现逻辑吗?如果是这样,有没有办法避免转换,if-else结构和/或向域模型添加其他属性(如第一个“解决方案”中的枚举)。

2 个答案:

答案 0 :(得分:1)

在一天结束时,您将基于子类型(具体类)进行分支,因为验证用户输入的逻辑基于子类中包含的那些特定详细信息。

泛型在这里并没有真正帮助你,因为泛型主要基于应用不同类型统一的逻辑,在通用接口上应用通用逻辑进行操作所有适用类型共享。在这里,您的逻辑和界面因每个子类型而异。

因此,您的主要选择是一个不可扩展的解决方案,您可以修改中央源代码(如大量ifs/elses,地图等),并根据子类型手动分支,或使用抽象/动态多态一个可扩展的解决方案,不需要修改任何中央源代码,也可以根据子类型自动分支。

如果你能负担得起,反射也可能是一条可能的路线(它在运行时有点贵),并且它可以适合为你提供集中实现的通用逻辑。

如果您不想将此validate方法添加到AbstractType及其所有子类型,那么您始终可以在顶部添加另一个抽象级别,其中包含validateValidatorB这样的方法,它实现IValidator接口并将TypeB的对象存储为成员,并应用用于使用TypeB's属性验证用户输入的逻辑。

答案 1 :(得分:0)

我上周研究了设计模式,我想提出我的解决方案(它有效,但我不确定这是解决问题的最明智的方法)。

我的解决方案的想法是使用工厂:您将模型(在您的情况下是JPA实体)提供给工厂,它为您提供了该模型的正确验证器。

在程序开始时,您必须通过寄存器方法告诉工厂哪个是程序的每个模型类的验证器类。

让我们从实施开始......

<强> AbstractModel.java

public abstract class AbstractModel
{
    private final int commonProperty;

    protected AbstractModel(int commonProperty)
    {
        this.commonProperty = commonProperty;
    }

    public int getCommonProperty() { return commonProperty; };
}

AbstractModel中我们放置了模型的所有常见属性。

<强> ModelA.java

public class ModelA extends AbstractModel
{
    private final int specificProperty1;
    private final int specificProperty2;

    public ModelA(int commonProperty, int specificProperty1, int specificProperty2)
    {
        super(commonProperty);

        this.specificProperty1 = specificProperty1;
        this.specificProperty2 = specificProperty2;
    }

    public int getSpecificProperty1() { return specificProperty1; }

    public int getSpecificProperty2() { return specificProperty2; }
}

ModelA有两个特定属性。

<强> ModelB.java

public class ModelB extends AbstractModel
{
    private final int specificProperty1;
    private final int specificProperty2;

    public ModelB(int commonProperty, int specificProperty1, int specificProperty2)
    {
        super(commonProperty);

        this.specificProperty1 = specificProperty1;
        this.specificProperty2 = specificProperty2;
    }

    public int getSpecificProperty1() { return specificProperty1; }

    public int getSpecificProperty2() { return specificProperty2; }
}

ModelB也有两个特定的属性。

假设a的{​​{1}}实例有效iff

ModelA

a.commonProperties == a.specificProperty1 + a.specificProperty2 的实例b有效iff

ModelB

<强> Validator.java

b.commonProperties == b.specificProperty1 * b.specificProperty2

验证器的一个非常简单的界面。

<强> AbstractValidator.java

public interface Validator
{
    public boolean validate();
}

这是包装要验证的模型的具体验证器的超类。

<强> ValidatorA.java

public abstract class AbstractValidator implements Validator
{
    private final AbstractModel toBeValidated;

    protected AbstractValidator(AbstractModel toBeValidated)
    {
        this.toBeValidated = toBeValidated;
    }

    protected AbstractModel getModel()
    {
        return toBeValidated;
    }
}

public class ValidatorA extends AbstractValidator { protected ValidatorA(AbstractModel toBeValidated) { super(toBeValidated); } public boolean validate() { ModelA modelA = (ModelA) getModel(); return modelA.getCommonProperty() == modelA.getSpecificProperty1() + modelA.getSpecificProperty2(); } }

实例的验证程序

<强> ValidatorB

ModelA

这是public class ValidatorB extends AbstractValidator { protected ValidatorB(AbstractModel toBeValidated) { super(toBeValidated); } public boolean validate() { ModelB modelB = (ModelB) getModel(); return modelB.getCommonProperty() == modelB.getSpecificProperty1() * modelB.getSpecificProperty2(); } }

实例的验证器

最后是工厂!

<强> ValidatorFactory.java

ModelB

工厂是单身,有两个重要的方法:

  1. public class ValidatorsFactory { private static ValidatorsFactory instance; private final HashMap<Class<? extends AbstractModel>, Class<? extends Validator>> registeredValidators; private ValidatorsFactory() { registeredValidators = new HashMap<Class<? extends AbstractModel>, Class<? extends Validator>>(); } public static ValidatorsFactory getInstance() { if (instance == null) instance = new ValidatorsFactory(); return instance; } public void registerValidator( Class<? extends AbstractModel> model, Class<? extends Validator> modelValidator) { registeredValidators.put(model, modelValidator); } public Validator createValidator(AbstractModel model) { Class<? extends Validator> validatorClass = registeredValidators.get(model.getClass()); Constructor<? extends Validator> validatorConstructor = null; Validator validator = null; try { validatorConstructor = validatorClass.getDeclaredConstructor(new Class<?>[] { AbstractModel.class }); validator = (Validator) validatorConstructor.newInstance(new Object[] { model }); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.err.println(e.getMessage()); // handle exception } return validator; } } registerValidator中添加新对(modelClass,validatorClass)。
  2. HashMap获取指定模型的正确验证器。
  3. 这是如何使用这种模式:

    createValidator

    输出:

    public class Main
    {
        public static void main(String args[])
        {
            ValidatorsFactory factory = ValidatorsFactory.getInstance();
    
            factory.registerValidator(ModelA.class, ValidatorA.class);
            factory.registerValidator(ModelB.class, ValidatorB.class);
    
            ModelA modelA = new ModelA(10, 4, 6);
            if (factory.createValidator(modelA).validate())
                System.out.println("modelA is valid");
            else
                System.out.println("modelA is not valid");
    
            ModelB modelB = new ModelB(10, 8, 2);
            if (factory.createValidator(modelB).validate())
                System.out.println("modelB is valid");
            else
                System.out.println("modelB is not valid");
        }
    }
    

    请注意,模型完全是从控制器中分离出来的,它只使用modelA is valid [because 10 = 4 + 6] modelB is not valid [because 10 != 8 * 2] 中的一个强制转换模型。

    希望它有所帮助!