首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Java模拟MixIns

用Java模拟MixIns
EN

Code Review用户
提问于 2015-04-19 15:52:09
回答 2查看 317关注 0票数 2

我使用以下技术来模拟混合(或特性)使用Java,并想知道这是合理的,或只是混淆未来的开发人员。此外,我相信一个好的命名方案是最好的文件,所以如果它将有助于改变命名,请提供建议。

代码语言:javascript
复制
/** A mixin interface which your class should implement */
public interface IsResizableMixin {

    /** 
     * The implementation, which your class should 
     * instance and delegate calls to
     */
    public static class IsResizableMixinImpl implements IsResizableMixin {

        // A widget is e.g. a Swing Component, a GWT Widget, etc.
        private Widget w;

        pubic IsResizableMixinImpl(Widget w) {
            this.w = w;
        }

        public void resizeTo(int width, int height);
            /* for example */
            w.setWidth(width);
            w.setHeight(height);
            w.getParent().redraw();
        }
    }

    void resizeTo(int width, int height);
}

然后是一个可调整大小的Widget的示例实现:

公共类Foo扩展Widget实现IsResizableMixin {私有IsResizableMixin混合;/* . */公共Foo() { super();this.mixin =新IsResizableMixinImpl(this);/* . */ /* . */ public mixin.resizeTo( int w,int h) { mixin.resizeTo(w,h);}}

一个更丰富的例子是一个Widget,它可以设置为“繁忙”,也就是说,覆盖一个旋转器和禁用的。

公共接口IsBusyMixin {公共类IsBusyMixinImpl实现IsBusyMixin {私有Widget w;私有布尔isBusy = false;pubic IsBusyMixinImpl(Widget ){ this.w .w= w;} public void toggleBusy();isBusy = !isBusy();如果(isBusy) { /*覆盖使用自旋器*/ } /* {/*删除自旋覆盖*/ }}空toggleBusy();}公共类Foo扩展Widget实现IsBusyMixin { //除此方法存在的事实以外,// Foo不知道可以切换到繁忙状态。公共空toggleBusy() { this.mixin.toggleBusy();}

这种办法的好处是:

  1. 代码重用。在过去,如果我们需要Foo功能,我们会复制粘贴样板代码,但是如果发现了一个bug,我们就会忘记复制它的地方。
  2. 委托实现可能有所不同;我们可以为Swing组件和GWT组件提供一个实现,但它们的API是相同的。
  3. 字段名不重叠,这是多重继承的问题之一。

这种方法的问题是:

  1. 可能会让人困惑。我的解决方案是记录并希望开发人员看到它。
  2. 方法名称重叠,这就是多重继承不好的原因(例如,Widget可能有一个getSize()方法,而IsResizeableMixin也可以声明一个getSize())。解决方案是给混合方法不同的名称。

这只是一个简单的例子。将boolean放到实现类中也同样有效,但我试图将其从Foo中考虑进去。如果我们决定改变状态的存储方式,所有的IsBusyMixins都需要更新。

我错过了什么利弊?

请注意,Java 8's默认接口实现不涵盖此用例,因为mixins必须保持某种状态。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-04-19 19:26:12

即使您需要一些额外的状态,也总是有选择的:

您可以将类直接添加到类中,并在接口中为类提供方法,或者使用解决方案。

直接添加到类中,如下所示:

代码语言:javascript
复制
public interface IsBusyMixin {
    boolean isBusy();
    void dumbToggleBusy();

    void overlayTheComponentWithASpinner(); // implement here or not

    void removeTheSpinnerOverlay(); // implement here or not

    public void toggleBusy();
        dumbToggleBusy();
        if (isBusy) {
            overlayTheComponentWithASpinner();
        } else {
            removeTheSpinnerOverlay();
        }
    }
}

public class Foo extends Widget implements IsBusyMixin {
    @Getter private boolean isBusy;
    public void toggleBusy() {
        isBusy = !isBusy();
    }
}

我想说,这总是有可能的。然而,它可能会变得比你的解决方案更丑陋。此外,所有接口方法都必须是公共的,这暴露了太多的内部状态。

因此,当事情变得更加复杂时,我不会滥用默认的方法,相反,我会使用您的方法。

然后,您可能会考虑使用一个默认的方法来公开mixin,或者另一个类似的方法

代码语言:javascript
复制
default void toggleBusy() {
    this.mixin().toggleBusy();
}

方法名称重叠,这就是多重继承不好的原因(例如,Widget可能有一个getSize()方法,IsResizeableMixin也可以声明一个getSize())。解决方案是给混合方法不同的名称。

如果其中一个方法总是委托另一个方法,则可能应该保持名称相同。否则,无论你做什么,它都会让你感到困惑。

IsResizeableMixin的名字可能应该是ResizeableResizeableMixin

票数 1
EN

Code Review用户

发布于 2015-04-19 17:24:55

您的混合器的状态是this本身,因此没有附加状态,您可以使用默认方法。

代码语言:javascript
复制
public interface IsResizableMixin {
    void setWidth(width);
    void setHeight(height);
    Redrawable setHeight(height);

    default void redrawParent() {
        getParent().redraw();
    }

    default void resizeTo(int width, int height) {
        setWidth(width);
        setHeight(height);
        redrawParent();
    }
}

public class Foo extends Widget implements IsResizeableMixin {
    // This class has been intentionally left empty.
}

从您的例子来看,我的Foo中没有遗漏什么。

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/87352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档