2017-03-06 152 views
0

的实例例如,我有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()(这是受保护的)构造函数< ...>?

+3

问问自己:什么是'宠物'应该通过'动物'做?你现在什么都不做,这就是为什么这个问题不清楚(不清楚你传递'动物'的理由是什么)。 – Tom

+0

@Tom说了些什么:关于你想达到什么的更多信息会很好。目前,这听起来像你可以使用'interface'的东西。 – domsson

+2

如果你想说要采用现有的'Animal'实例并追溯**将该实例**转换为'Pet',则不能这样做。你可以创建一个新的'Pet',它是从一个'Animal'实例初始化的,但它将是分开的。实例的类在创建时被锁定。 (我们可以对[接口]有不同的视图,有些代码可能只知道它是'Animal',其他代码可能知道它是'Cat',但*实例*在创建时具有特定的类集。 –

回答

1

即使在您编辑之后,您的意图对我来说也不是很清楚。看起来好像你只是想找到一种方法,允许你在运行时说:“这只猫以前是流浪的,但它现在只是一个人的宠物!”。

如果这是正确的,你可以去一个非常简单和直接的解决方案 - 添加此功能从右到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()方法。或者,如果方法没有被覆盖,或许你对静默动物的默认行为没有问题。

编辑2This answer到相关的问题可能会对您的情况更清楚。它是关于C#的,但原理转化为Java。

+0

我重新编辑了我的编辑,现在它正确显示我想要的内容 – Noqrax

+0

并非如此。你向我们展示了一些你想要工作的代码,但不是它背后的* intent *。如果我正确读了它,意图是:“我想能够判断某只动物是不是宠物,并根据它来采取行动”。这可以用上面显示的代码。 – domsson

0

你描述的是完全可能的,俗称“装饰模式”。

仅限链接的答案很糟糕,稍后我会详细阐述时间。

同时,维基百科有更多信息: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) ...总是叮叮当当的“访客” - 也是。

+0

'makeNoise()'上的优点 - 以前完全忽略了。现在编辑我的答案。 – domsson