在派生中为成员变量使用派生类型 class
Use derived type for member variable in derived class
我目前有一个 class A,它有一些我想在 B 中使用的功能。A 有一个 Button 类型的成员变量,而在 B 中我想使用 IconButton 类型(派生来自按钮)。
class是这样的:
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
中可用,因此我需要通过提供方法 "workaround" 在 B 中执行 "workaround" =16=].
是的,通常我们在 A 中也会有一个 getButton()
方法,所以这不是对 B 的牵强附会。
但我想知道,这真的是正确的做法还是我做错了?
我也想过创建一个摘要 class,例如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()
或类似的东西,但它会变成一个全新的错误做法。
一种简单(和多态)的方法是覆盖 class B 中的 getButton
和 return IconButton
的实例,而不是在 class,例如:
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;
}
}
您的解决方法是个坏主意。你失去了很多类型安全。你可以例如将 B
的构造函数更改为 x = new Button();
并忘记强制转换。您的程序仍然可以编译但在运行时失败。
我认为您在通用泛型超类方面走在正确的轨道上。您可以将 A0
定义为带有成员 T x
的 A0<T extends Button>
。可能有更好的解决方案,但没有大局就很难说。
- 提取按钮界面
public interface Button {
void init();
}
- 创建 PlainButton(您的前 Button)class:
public class PlainButton implements Button {
public void init() {
xx();
}
private void xx() {
}
}
- 创建 IconButton class:
public class IconButton implements Button {
public void init() {
yy();
zz();
}
private void yy() {
}
private void zz() {
}
}
- 创建 ButtonWrapper class(你的前 A and/or B classes):
public class ButtonWrapper {
private final T button;
public ButtonWrapper(T button) {
this.button = button;
this.button.init();
}
public T getButton() {
return button;
}
}
使用:
ButtonWrapper A = new ButtonWrapper(new PlainButton());
ButtonWrapper B = new ButtonWrapper(new IconButton());
如果您唯一关心的是 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
}
不需要抽象基础class、泛型、包装器。让 B 拥有它的 IconButton,并有 2 个引用(B.ib
和继承 A.b
)
如果您不想使用泛型:
这种方法违背了 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;
}
}
我目前有一个 class A,它有一些我想在 B 中使用的功能。A 有一个 Button 类型的成员变量,而在 B 中我想使用 IconButton 类型(派生来自按钮)。
class是这样的:
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
中可用,因此我需要通过提供方法 "workaround" 在 B 中执行 "workaround" =16=].
是的,通常我们在 A 中也会有一个 getButton()
方法,所以这不是对 B 的牵强附会。
但我想知道,这真的是正确的做法还是我做错了?
我也想过创建一个摘要 class,例如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()
或类似的东西,但它会变成一个全新的错误做法。
一种简单(和多态)的方法是覆盖 class B 中的 getButton
和 return IconButton
的实例,而不是在 class,例如:
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;
}
}
您的解决方法是个坏主意。你失去了很多类型安全。你可以例如将 B
的构造函数更改为 x = new Button();
并忘记强制转换。您的程序仍然可以编译但在运行时失败。
我认为您在通用泛型超类方面走在正确的轨道上。您可以将 A0
定义为带有成员 T x
的 A0<T extends Button>
。可能有更好的解决方案,但没有大局就很难说。
- 提取按钮界面
public interface Button { void init(); }
- 创建 PlainButton(您的前 Button)class:
public class PlainButton implements Button { public void init() { xx(); } private void xx() { } }
- 创建 IconButton class:
public class IconButton implements Button { public void init() { yy(); zz(); } private void yy() { } private void zz() { } }
- 创建 ButtonWrapper class(你的前 A and/or B classes):
public class ButtonWrapper { private final T button; public ButtonWrapper(T button) { this.button = button; this.button.init(); } public T getButton() { return button; } }
使用:
ButtonWrapper A = new ButtonWrapper(new PlainButton()); ButtonWrapper B = new ButtonWrapper(new IconButton());
如果您唯一关心的是 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
}
不需要抽象基础class、泛型、包装器。让 B 拥有它的 IconButton,并有 2 个引用(B.ib
和继承 A.b
)
如果您不想使用泛型:
这种方法违背了 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;
}
}