在派生类中使用派生类型作为成员变量

时间:2017-06-16 13:35:53

标签: java oop gwt object-oriented-analysis

我目前有一个A类,它有一些我想在B中使用的功能.A有一个Button类型的成员变量,而在BI中想要使用IconButton类型(从Button派生)。

课程是这样的:

public class A {

    protected Button x = new Button();

    A() {
        x.xx();
    }

    public void doFirstThing() {
        x.xx();
    }

    Button getButton() {
        return x;
    }
}

public class B extends A {

    B() {
        x = new IconButton();

        getButton().yy();
    }

    public void doSecondThing() {
        getButton().zz();
    }

    IconButton getButton() {
        return (IconButton) x;
    }
}

public class Button {

    public void xx() {

    }   
}

public class IconButton extends Button {

    public void yy() {

    }

    public void zz() {

    }
}

正如您所看到的,方法yy()zz()仅在IconButton中可用,因此我需要通过提供方法getButton在B中执行“解决方法”

是的,通常我们在A中也有getButton()方法,所以这对B来说并不是一个牵强附会的方法。

但我想知道,这是不是正确的做法,或者我做错了?

我还想过创建一个抽象类,例如A0,它将包含来自A的当前代码。然后我只做:

class A extends A0<Button> {
 // mostly empty, code taken from A0
}

class B extends A0<IconButton> {
// custom things here
}

还有其他方法可以解决这个问题吗?

这是我的GWT应用中的一个组件。所以,如果我声明像@king_nak说的那样,那么我的组件中会有两个按钮。或者如果我可以使用另一种解决方法,我可以删除B中的原始按钮,例如x.removeFromParent()或类似的东西,但它只会成为一个全新的糟糕做法。

5 个答案:

答案 0 :(得分:1)

你的解决方法是一个坏主意。你失去了很多类型的安全。你可以,例如将B的构造改为x = new Button();并忘记演员。您的程序仍然可以编译但在运行时失败。

我认为你使用普通的通用超类是在正确的轨道上。您可以将A0定义为A0<T extends Button>,其成员为T x。可能有一个更好的解决方案,但如果没有大局,很难说清楚。

答案 1 :(得分:0)

一种简单(多态)的方法是覆盖B类中的getButton并返回IconButton的实例,而不是在类中有引用,例如:

public class A {
    public Button getButton(){
        Button b = new Button();
        b.xx();
        return b;
    }
}

public class B extends A {

    @Override
    public Button getButton(){
        IconButton b = new IconButton();
        b.yy();
        b.zz();
        return b;
    }
}

答案 2 :(得分:0)

  1. 提取按钮界面
    public interface Button {
        void init();
    }
    
  2. 创建PlainButton(您的前按钮)类:
    public class PlainButton implements Button {
        public void init() {
            xx();
        }
        private void xx() {
        }
    }
    
  3. 创建IconButton类:
    public class IconButton implements Button {
        public void init() {
            yy();
            zz();
        }
        private void yy() {
        }
        private void zz() {
        }        
    }
    
  4. 创建ButtonWrapper类(您的前A和/或B类):
    public class ButtonWrapper {
        private final T button;
        public ButtonWrapper(T button) {
            this.button = button;
            this.button.init();
        }
        public T getButton() {
            return button;
        }
    }
    
  5. 使用:

    ButtonWrapper A = new ButtonWrapper(new PlainButton());
    ButtonWrapper B = new ButtonWrapper(new IconButton());
    

答案 3 :(得分:0)

如果你唯一担心的是B应该有一个IconButton而不是它Button,为什么不在B中为它创建一个单独的成员,并让A用那个?

class A {
    protected Button b;
    public A() {
      // By default, I use a Button
      b = new Button();
    }

    // Subclasses can override which button I use
    protected A(Button b) {
       this.b = b;
    }

}

class B extends A {
    private IconButton ib;
    public B() {
      super(new IconButton());
      ib = (IconButton) super.b;
    }

    // B can access it's IconButton through ib
    // Users of A will see a Button
}

不需要抽象基类,泛型,包装器。让B拥有它的IconButton,并有2个引用它(B.ib并继承A.b

答案 4 :(得分:0)

如果您不想使用泛型: 这种方法与best practices相反,但只要你不使用按钮在B的构造函数中做任何事情,我就会发现它完全没问题:

public static class A {

    protected Button x = null;

    public A() {
        x = createButton();
    }

    public Button getButton() {
        return x;
    }

    protected Button createButton(){
        Button result = new Button();
        result.xx();
        return result;
    }
}

public static class B extends A{

    public IconButton getButton() {
        return (IconButton)x;
    }

    protected Button createButton(){
        IconButton iconButton = new IconButton();
        iconButton.yy();
        iconButton.zz();
        return iconButton;
    }
}

现在,如果你想避免演员表演,你可以使用这种我很可能不会自己使用的疯狂方法。 警告使用风险由您自行承担:

public static class A {

        protected Button x = null;

        public A() {
            x = createButton();
        }

        public Button getButton() {
            return x;
        }

        protected Button createButton(){
            Button result = new Button();
            result.xx();
            return result;
        }
    }

    public static class B extends A{

        //leave uninitialized so that when B gets constructed iconButton wont be reinitialized because it has been initialized by A's constructor call
        private IconButton iconButton; 

        public IconButton getButton() {
            return iconButton;
        }

        protected Button createButton(){
            iconButton = new IconButton();
            iconButton.yy();
            iconButton.zz();
            return iconButton;
        }
    }

<强>更新

如上所述,首选方法是避免继承,并在需要时使用组合。但是由于示例代码没有太多细节以便能够显示组合方法,我添加了另一种仍然使用继承的方法,避免了强制转换和构造初始化。 我认为最好在使用非并发框架(如Swing或GWT)而不是构造初始化时使用延迟初始化:

public static class A {

        private Button x = null;

        protected Button getButton() {
            if (x == null) x = createButton();
            return x;
        }

        private Button createButton(){
            Button result = new Button();
            result.xx();
            return result;
        }
    }

    public static class B extends A{

        private IconButton iconButton; 

        public Button getButton() {
            if (iconButton == null) iconButton = createButton();
            return iconButton;
        }

        public IconButton getIconButton(){
            getButton();
            return iconButton;
        }

        private IconButton createButton(){
            IconButton iconButton = new IconButton();
            iconButton.yy();
            iconButton.zz();
            return iconButton;
        }
    }