是否可以扩展类
的实例例如,我有Animal类,Cat类(Bird,Dog,Fish ...),它扩展了Animal。现在我想宣布宠物类,这也是动物类,我希望它可以用任何现有的动物来构建,例如猫。是否可以扩展类
所以我需要构造是这样的:
class Pet extends Animal{
private String nickname;
private Animal kind;
Pet(Animal a, String nickname){
<...>;
this.nickname = nickname;
}
}
编辑: 我想是这样的:
Cat cat = new Cat();
Animal pet = new Pet(cat, "Foo");
if (pet instanceof Pet){
if (pet.kind instanceof Cat){
Pet.sayMeow();
}
}
是不是意味着我只需要Animal()
(这是受保护的)构造函数< ...>?
即使在您编辑之后,您的意图对我来说也不是很清楚。看起来好像你只是想找到一种方法,允许你在运行时说:“这只猫以前是流浪的,但它现在只是一个人的宠物!”。
如果这是正确的,你可以去一个非常简单和直接的解决方案 - 添加此功能从右到Animal
类:
public class Animal {
private boolean isPet = false;
private String nickname = "";
public Animal() {
/*...*/
}
public makeStray() {
isPet = false;
nickname = "";
}
public makePet(String nickname) {
isPet = true;
this.nickname = nickname;
}
public boolean isPet() {
return isPet;
}
public void makeNoise() {
/* Override in child classes */
}
}
根据你的榜样,然后你可以简单地做:
Animal cat = new Cat();
cat.makePet("Foo");
if (cat.isPet()) { // Apparently, only pet cats ever meow.
cat.makeNoise(); // Cats will meow, dogs will bark, ...
}
但是,请注意,这种编码方式可以快速膨胀一个类。这实际上取决于你打算如何处理它。我会说这是快速'n'脏解决方案。
对于更复杂的解决方案,请检查其他答案。
EDIT1:正如Fildor正确指出的,有一个方法sayMeow()
不是一个好主意。在Animal
中最好有makeNoise()
方法,并在子类中重写它以获取不同类型动物的特定行为。现在,如果您从不想实际创建Animal
类的实例,则还可以创建类abstract
以及makeNoise()
方法。这将确保每个孩子班级都必须实施makeNoise()
方法。或者,如果方法没有被覆盖,或许你对静默动物的默认行为没有问题。
编辑2:This answer到相关的问题可能会对您的情况更清楚。它是关于C#的,但原理转化为Java。
你描述的是完全可能的,俗称“装饰模式”。
仅限链接的答案很糟糕,稍后我会详细阐述时间。
同时,*有更多信息:Decorator Pattern。
1 Cat cat = new Cat();
2 Animal pet = new Pet(cat, "Foo");
3 if (pet instanceof Pet){
4 if (pet.kind instanceof Cat){
5 Pet.sayMeow();
6 }
7 }
这有你需要使用instanceOf
的缺点。通常,你会让你的Animal
类有一个方法 - 我们称之为makeNoise
。可能是抽象的。您动物实现(Cat
,Dog
...)然后将覆盖该方法,使其各自的噪音(“树皮”,“喵”...)。
在片段中,似乎只有宠物可以发出噪音......这使得它有点复杂,因为会有多种方式来做到这一点。
您可以让装饰者保存声音并覆盖makeNoise来发出声音。像这样:
Cat catInstance = new Cat();
catInstance.makeNoise(); // Default impl: NOP => "" - no sound.
Animal pet = new Pet(catInstance, "Mieow");
pet.makeNoise(); // => "Mieow"
这一切的一点是:你想避免使用instanceof
。你不在乎动物是猫还是猫,宠物猫还是宠物狗。如果告诉他们,他们应该发出正确的声音。所以你可以有一个“动物”的集合,告诉他们所有的“makeNoise”,每个人都将保持沉默,吠叫或mieow,而不必关心他们是否是宠物或Animal
的特定孩子。
编辑:再次读我的答案,它更像是一个政策(策略模式)比装饰者。 该策略会改变如何完成某些操作,而装饰器将添加该功能。
所以要成为一个真正的装饰者,这将意味着makeNoise
将在Pet
的界面。这意味着你无法在动物上调用该方法。
这就是为什么我改变我的建议从“装饰”到“Strategy”模式。
上面的例子仍然成立。你会有一种“默认”的策略,并通过使用装饰类实现方法来注入“宠物”策略。
当然,所有这些也可以用不同的方式来更严格地实现模式。
最后,if(x instanceof X) ...
总是叮叮当当的“访客” - 也是。
'makeNoise()'上的优点 - 以前完全忽略了。现在编辑我的答案。 – domsson
问问自己:什么是'宠物'应该通过'动物'做?你现在什么都不做,这就是为什么这个问题不清楚(不清楚你传递'动物'的理由是什么)。 – Tom
@Tom说了些什么:关于你想达到什么的更多信息会很好。目前,这听起来像你可以使用'interface'的东西。 – domsson
如果你想说要采用现有的'Animal'实例并追溯**将该实例**转换为'Pet',则不能这样做。你可以创建一个新的'Pet',它是从一个'Animal'实例初始化的,但它将是分开的。实例的类在创建时被锁定。 (我们可以对[接口]有不同的视图,有些代码可能只知道它是'Animal',其他代码可能知道它是'Cat',但*实例*在创建时具有特定的类集。 –