0

我有一个值类型Commission,它是更大的编辑器图表的一部分:

public class Commission implements Serializable
{
    private CommissionType commissionType; // enum
    private Money value; // custom type, backed by BigDecimal
    private Integer multiplier;
    private Integer contractMonths;

    // ...
}

我想要实现的是最初只显示commissionType枚举的下拉列表,然后选择适当的子编辑器来根据所选值编辑其余字段:

已选择 CommissionType.UNIT_RATE

已选择 CommissionType.STANDING_CHARGE

我之前使用 an实现了多个子类型编辑器(请参阅此处的问题AbstractSubTypeEditor),但这种情况略有不同,因为我没有编辑子类,它们都编辑相同的基本Commission类型,并且由于某种原因,相同的方法似乎不适用于多个编辑器编辑相同的具体类型。

我目前有两个子编辑器(实现Editor<Commission>IsWidget通过自定义界面IsCommissionEditorWidget),但它们本身有不同的子编辑器,因为Money可以是便士或英镑,乘数可以代表天或月,以及其他变化。

委员会编辑

我已经查看了这个问题中的类似问题,并尝试创建一个CompositeEditor<Commission, Commission, Editor<Commission>>.

这就是我到目前为止所得到的(注意注释掉的部分是通过实现和LeafValueEditor<Commission>手动调用setValue()and getValue()onamount和来获得我想要的功能的黑客方式):multipliercontractMonths

public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, Editor<Commission>>, //LeafValueEditor<Commission>
{
    interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    CommissionTypeEditor commissionType;

    @UiField
    Panel subEditorPanel;

    private EditorChain<Commission, Editor<Commission>> chain;
    private IsCommissionEditorWidget subEditor = null;
    private Commission value = new Commission();

    public CommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));

        commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
    }

    @Override
    public void setValue(Commission value)
    {
        Log.warn("CommissionEditor -> setValue(): value is " + value);

        chain.detach(subEditor);

        commissionType.setValue(value.getCommissionType());

        if(value.getCommissionType() != null)
        {
            switch(value.getCommissionType())
            {
                case UNIT_RATE:
                    Log.info("UNIT_RATE");
                    subEditor = new UnitRateCommissionEditor();
                    break;
                case STANDING_CHARGE:
                    Log.info("STANDING_CHARGE");
                    subEditor = new StandingChargeCommissionEditor();
                    break;
                case PER_MWH:
                    Log.info("PER_MWH");
                    // TODO
                    break;
                case SINGLE_PAYMENT:
                    Log.info("SINGLE_PAYMENT");
                    // TODO
                    break;
            }

            this.value = value;
            subEditorPanel.clear();
//            subEditor.setValue(value);
            subEditorPanel.add(subEditor);
            chain.attach(value, subEditor);
        }

    }

//    @Override
//    public Commission getValue()
//    {
//        if(subEditor != null)
//        {
//            return subEditor.getValue();
//        }
//        else
//        {
//        return value;
//        }
//    }

    @Override
    public void flush()
    {
        this.value = chain.getValue(subEditor);
    }

    @Override
    public void setEditorChain(EditorChain<Commission, Editor<Commission>> chain)
    {
        this.chain = chain;
    }

    @Override
    public Editor<Commission> createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public String getPathElement(Editor<Commission> commissionEditor)
    {
        return "";
    }

    @Override
    public void onPropertyChange(String... strings)
    {

    }

    @Override
    public void setDelegate(EditorDelegate<Commission> editorDelegate)
    {

    }

}

这是IsCommissionEditorWidget定义每个子编辑器的合同的界面,也可以添加到面板中:

public interface IsCommissionEditorWidget extends Editor<Commission>, IsWidget
{

}

UnitRateCommissionEditor

当用户选择CommissionType.UNIT_RATE时,我想将其添加到编辑器链中以应用于剩余的 3 个字段:

public class UnitRateCommissionEditor extends Composite implements IsCommissionEditorWidget
{
    interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPenceBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public UnitRateCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

//    @Override
//    public void setValue(Commission commission)
//    {
//        amount.setValue(commission.getAmount());
//        multiplier.setValue(commission.getMultiplier());
//        contractMonths.setValue(commission.getContractMonths());
//    }
//
//    @Override
//    public Commission getValue()
//    {
//        return new Commission(CommissionType.UNIT_RATE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
//    }
}

常设收费委员会编辑

什么时候CommissionType.STANDING_CHARGE选择我想要这个(UiBinders 也有点不同,但主要区别是MoneyPoundsBox不是MoneyPenceBox):

public class StandingChargeCommissionEditor extends Composite implements IsCommissionEditorWidget
{
    interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPoundsBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public StandingChargeCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

//    @Override
//    public void setValue(Commission commission)
//    {
//        amount.setValue(commission.getAmount());
//        multiplier.setValue(commission.getMultiplier());
//        contractMonths.setValue(commission.getContractMonths());
//    }
//
//    @Override
//    public Commission getValue()
//    {
//        return new Commission(CommissionType.STANDING_CHARGE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
//    }
}

目前flush(),父类型的 (正在编辑的包含 的类型Commission)返回一个带有未定义amountmultiplier的佣金contractMonths。我可以让这些值传入和传出的唯一方法是手动将其编码(注释代码)。

  • 我的副编辑器EditorChain是否正确附加?

编辑 1:提出的解决方案

我决定创建一个新的中间类,分别包装每个子类型的佣金,就像AbstractSubTypeEditor我在这个问题中所做的那样

委员会编辑

仍然是 a CompositeEditor,但它只有一个或零个子编辑器,它只会是 a CommissionSubtypeEditor

public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, CommissionSubtypeEditor>, LeafValueEditor<Commission>
{
    interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    @Ignore
    CommissionTypeEditor commissionType;

    @UiField
    Panel subEditorPanel;

    private EditorChain<Commission, CommissionSubtypeEditor> chain;

    @Ignore
    @Path("")
    CommissionSubtypeEditor subEditor = new CommissionSubtypeEditor();

    private Commission value;

    public CommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));

        commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
    }

    @Override
    public void setValue(Commission value)
    {
        Log.warn("CommissionEditor -> setValue(): value is " + value);

        commissionType.setValue(value.getCommissionType());

        if(value.getCommissionType() != null)
        {
            this.value = value;
            subEditorPanel.clear();
            subEditorPanel.add(subEditor);
            chain.attach(value, subEditor);
        }

    }

    @Override
    public Commission getValue()
    {
        Log.info("CommissionEditor -> getValue: " + value);
        return value;
    }

    @Override
    public void flush()
    {
        chain.getValue(subEditor);
    }

    @Override
    public void setEditorChain(EditorChain<Commission, CommissionSubtypeEditor> chain)
    {
        this.chain = chain;
    }

    @Override
    public CommissionSubtypeEditor createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public String getPathElement(CommissionSubtypeEditor commissionEditor)
    {
        return "";
    }

    @Override
    public void onPropertyChange(String... strings)
    {

    }

    @Override
    public void setDelegate(EditorDelegate<Commission> editorDelegate)
    {

    }

}

AbstractSubTypeEditor

这门课归功于 Florent Bayle 。我不认为我可以在没有多态子类型的情况下使用它,但它似乎工作得很好。本质上允许包装子编辑器,如下所示CommissionSubtypeEditor

public abstract class AbstractSubTypeEditor<T, C extends T, E extends Editor<C>> implements CompositeEditor<T, C, E>, LeafValueEditor<T>
{
    private EditorChain<C, E> chain;
    private T currentValue;
    private final E subEditor;

    public AbstractSubTypeEditor(E subEditor)
    {
        this.subEditor = subEditor;
    }

    @Override
    public E createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public void flush()
    {
        currentValue = chain.getValue(subEditor);
    }

    @Override
    public String getPathElement(E subEditor)
    {
        return "";
    }

    @Override
    public T getValue()
    {
        return currentValue;
    }

    @Override
    public void onPropertyChange(String... paths)
    {
    }

    @Override
    public void setDelegate(EditorDelegate<T> delegate)
    {
    }

    @Override
    public void setEditorChain(EditorChain<C, E> chain)
    {
        this.chain = chain;
    }

    public void setValue(T value, boolean instanceOf)
    {
        if(currentValue != null && value == null)
        {
            chain.detach(subEditor);
        }
        currentValue = value;
        if(value != null && instanceOf)
        {
            chain.attach((C) value, subEditor);
        }
    }
}

佣金子类型编辑器

public class CommissionSubtypeEditor extends Composite implements Editor<Commission>
{

    interface Binder extends UiBinder<HTMLPanel, CommissionSubtypeEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    Panel subEditorPanel;

    @Ignore
    final UnitRateCommissionEditor unitRateCommissionEditor = new UnitRateCommissionEditor();

    @Path("")
    final AbstractSubTypeEditor<Commission, Commission, UnitRateCommissionEditor> unitRateWrapper = new AbstractSubTypeEditor<Commission, Commission,
            UnitRateCommissionEditor>(unitRateCommissionEditor)
    {
        @Override
        public void setValue(Commission value)
        {
            if(value.getCommissionType() == CommissionType.UNIT_RATE)
            {
                Log.info("unitRateWrapper setValue");
                setValue(value, true);

                subEditorPanel.clear();
                subEditorPanel.add(unitRateCommissionEditor);

            }
        }
    };

    @Ignore
    final StandingChargeCommissionEditor standingChargeCommissionEditor = new StandingChargeCommissionEditor();

    @Path("")
    final AbstractSubTypeEditor<Commission, Commission, StandingChargeCommissionEditor> standingChargeWrapper = new AbstractSubTypeEditor<Commission,
            Commission, StandingChargeCommissionEditor>(standingChargeCommissionEditor)
    {
        @Override
        public void setValue(Commission value)
        {
            if(value.getCommissionType() == CommissionType.STANDING_CHARGE)
            {
                Log.info("standingChargeWrapper setValue");
                setValue(value, true);

                subEditorPanel.clear();
                subEditorPanel.add(standingChargeCommissionEditor);

            }
        }
    };

    public CommissionSubtypeEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

UnitRateCommissionEditor 和 StandingChargeCommissionEditor

既简单又实用Editor<Commission>

public class UnitRateCommissionEditor extends Composite implements Editor<Commission>
{
    interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPenceBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public UnitRateCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

差不多好了...

public class StandingChargeCommissionEditor extends Composite implements Editor<Commission>
{
    interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPoundsBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public StandingChargeCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

这确实有效,并且类似于我很早就尝试使用AbstractSubtypeEditorsCompositeEditor本身时尝试的方法。我认为那里的问题是编辑无法自行调用setValue()。我对吗?

非常感谢评论、批评和建议。

4

1 回答 1

2

您的复合编辑器被声明为CompositeEditor<Commission, Commission, Editor<Commission>>,这意味着该链将有望提供一些任意Editor<Commission>的。这是一个问题,因为编译器检查类型Editor<Commission>并且看不到子编辑器,也看不到其他编辑器接口(LeafValueEditor,ValueAwareEditor等),因此不绑定任何内容。

您提到您有两种不同Editor<Commission>的子类型 - 但代码生成器无法提前知道这一点,并且检查每个可能的子类型并构建任何可能适合的接线是没有意义的。无论好坏,编辑器框架都是静态的——预先声明所有内容,然后生成器将只创建所需的内容。

我看到的两个选项:

  • 要么创建两个不同的 CompositeEditor,每个子编辑器类型一个,并确保一次只附加一个,或者
  • 从两个编辑器中提取一个共同的超类型/接口,它们具有一致的命名和类型化方法,这些方法返回相同的编辑器类型(永远不会Editor<Foo>因为与上述相同的原因而返回)。这可能会更难做到,但你可能会用它来包装ValueAwareEditor和使用setValueflush()覆盖细节。
于 2016-07-29T13:48:41.733 回答