Java 对派生类中的成员变量使用派生类型
我现在有一个类a,它有一些我想在B中使用的功能。a有一个Button类型的成员变量,而在B中我想使用IconButton类型(从Button派生) 课程如下:Java 对派生类中的成员变量使用派生类型,java,oop,gwt,object-oriented-analysis,Java,Oop,Gwt,Object Oriented Analysis,我现在有一个类a,它有一些我想在B中使用的功能。a有一个Button类型的成员变量,而在B中我想使用IconButton类型(从Button派生) 课程如下: public class A { protected Button x = new Button(); A() { x.xx(); } public void doFirstThing() { x.xx(); } Button getButton()
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
}
A类扩展A0{
//大部分为空,代码取自A0
}
B类扩展A0{
//在这里定制东西
}
或者有没有其他更好的方法来解决这个问题
这是我的GWT应用程序中的一个组件。所以,如果我像@king_-nak所说的那样声明,那么我的组件中将有两个按钮。或者,如果我还可以接受另一种解决方法,我可以删除B中的原始按钮,例如x.removeFromParent()
或类似的东西,但这样做只会成为一个全新的坏习惯。一个简单的(多态的)方法是重写类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;
}
}
你的变通办法是个坏主意。你失去了很多打字安全。例如,您可以将
B
的结构更改为x=new Button()代码>并忘记演员阵容。您的程序仍将编译,但在运行时失败
我认为您使用通用超类是正确的。您可以使用成员tx
将A0
定义为A0
。也许有更好的解决方案,但如果没有大局,很难判断
提取按钮界面
public interface Button {
void init();
}
公共界面按钮{
void init();
}
创建PlainButton(您的ex Button)类:
公共类PlainButton实现了这个按钮{
公共void init(){
xx();
}
私有无效xx(){
}
}
创建图标按钮类:
public class PlainButton implements Button {
public void init() {
xx();
}
private void xx() {
}
}
public class IconButton implements Button {
public void init() {
yy();
zz();
}
private void yy() {
}
private void zz() {
}
}
公共类IconButton实现按钮{
公共void init(){
yy();
zz();
}
私人无效yy(){
}
私人空间zz(){
}
}
创建ButtonRapper类(您的ex A和/或B类):
公共类按钮敲击器{
专用最终T按钮;
公用按钮振打器(T按钮){
this.button=按钮;
this.button.init();
}
公共getButton(){
返回按钮;
}
}
使用:
ButtonWrapper A = new ButtonWrapper(new PlainButton());
ButtonWrapper B = new ButtonWrapper(new IconButton());
ButtonRapper A=新按钮Rapper(新的PlainButton());
ButtonRapper B=新按钮Rapper(新图标按钮());
如果您唯一关心的是B
应该有一个IconButton
而不是它的基本按钮,为什么不在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拥有它的图标按钮,并有2个对它的引用(B.ib
和继承的A.B
),以防您不想使用泛型:
这种方法与此相反,但我发现只要您不使用按钮在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;
}
}
关于抽象类A
和字段Tx
,以及类B扩展了类A
,我不确定您是否打算在某个时刻构造类A
的实例。如果是这样的话,那么就可以了,除了不需要IconButton getButton()
。如果不创建A
的实例,则将其抽象为是IconButton是B的一个实现细节。为什么要向这些类的客户端公开IconButton和Button?在这种情况下,如果你问我的话,有一些工厂设计模式会导致更干净的代码。如果getButton
方法返回的实例类型取决于重写它的类,那么我宁愿采用这种方式,而不是实现工厂方法。如果类型(这取决于类),为什么要这样做是否从按钮继承?一个干净的方法是一个接口,但我不确定在这种情况下,因为我看不清楚OP的缩进。呵呵,在设计软件解决方案时,这种讨论是很常见的。@DarshanMehta:我想你没有抓住我问题的重点。事实上,我并不关注getButton()。这只是我试图在B中使用x进行欺骗的一个例子。根本问题是x可以在A和B中的许多地方调用,因此我不认为我们可以像这样将事情“分组”到getButton方法:(啊……我忘了提到这是我的GWT应用程序中的一种组件。因此,如果我像你说的那样声明,那么我的组件中将有两个按钮……(或者如果我可以接受另一种解决方法,我可以删除B中的原始按钮。但这只是一种全新的坏做法)实例化B时只有一个按钮。当子类提供按钮时,A从不创建按钮。或者你正在处理生成的代码,不能使用这种方法?哇……看起来这就是我需要的。
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;
}
}