簡體   English   中英

在數據處理期間避免類型轉換

[英]Avoid Type Casting During Data Processing

我似乎無法找出解決以下問題的最佳方法。 假設有一個帶有幾個具體子類的抽象基類:

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); } 

因此,在兩種情況下都存在強制轉換。 在第一種情況下,沒有巨大的if-then結構,但是邏輯和域沒有分開。 在第二種情況下,if-then結構非常不靈活。

最后,這是我的問題。 我真的應該避免直接在域內實現邏輯嗎? 如果是這樣,有什么方法可以避免強制轉換,if-else結構和/或向域模型添加其他屬性(例如第一個“解決方案”中的枚舉)。

歸根結底,您將基於子類型(具體類)進行分支,因為驗證用戶輸入的邏輯基於子類中包含的那些特定詳細信息。

泛型在這里並沒有真正幫助您,因為泛型主要基於應用在不同類型之間統一的邏輯,並在應用於所有適用類型共享的通用接口的 通用邏輯上進行操作。 在這里,每個子類型的邏輯和接口都不同。

因此,您的主要選擇是一個不可擴展的解決方案,在該解決方案中,您正在修改中央源代碼(例如一大堆ifs/elses ,map等)並根據子類型進行手動分支,或者使用抽象/動態多態性作為可擴展的解決方案,不需要修改任何中央源代碼,並根據子類型自動分支。

如果您能夠負擔得起(也可能需要花很多時間)(在運行時這會花費一些錢),並且提供給您的是可以集中實現的通用邏輯,那么反思可能也是一條可行的途徑。

如果您不想將此validate方法添加到AbstractType及其所有子類型,則可以始終在其上添加另一個抽象級別,該抽象級別確實包含諸如ValidatorBvalidate方法,該方法實現IValidator接口並將TypeB對象存儲為成員,並使用TypeB's屬性應用用於驗證用戶輸入的邏輯。

我上周研究了設計模式,我想提出我的解決方案(它可以工作,但我不確定這是解決問題的最明智的方法)。

我的解決方案的想法是使用工廠:您將模型(在您的情況下為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也具有兩個特定的屬性。


假設ModelA的實例a是有效的

a.commonProperties == a.specificProperty1 + a.specificProperty2

並且ModelB的實例b是有效的iff

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

Validator.java

public interface Validator
{
    public boolean validate();
}

驗證程序一個非常簡單的界面。

AbstractValidator.java

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

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

    protected AbstractModel getModel()
    {
        return toBeValidated;
    }
}

這是包裝要驗證模型的具體驗證器的超類。

ValidatorA.java

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();
    }
}

ModelA實例的驗證器。

ValidatorB

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();
    }
}

這是ModelB實例的驗證器。


終於到了工廠!


ValidatorFactory.java

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; 
    }
}

工廠是單例,有兩種重要方法:

  1. registerValidatorHashMap添加新對(modelClass,validatorClass)。
  2. 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]

請注意,該模型與控制器完全分離,並且僅使用從AbstractModel到具體模型的一種轉換。

希望能幫助到你!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM