I'm supposed to have a hierarchy of animals in my java project, but I'm confused on what should extend what.
Here are the instructions:
Write classes or interfaces to represent the following:
Adoptable
Animal
Bat
Bird
BlueWhale
Dog
Emu
Fish
Goldfish
Mammal
Otter
Parakeet
Reptile
Turtle
WaterDweller
Whale
Winged
You need to decide on the structure of the classes/interfaces. Consider:
Which should be an abstract class? a concrete class? Which should be
an interface? How should the classes be related through inheritance?
In what classes should methods be placed? What methods should be
overridden? What information should be taken in as a parameter and
what information can be hard-coded into a class? Some additional
details/requirements:
All animals have a method "isWarmBlooded" that returns a boolean. The
method can be in the class directly or inherited. All animals have a
name. All classes have a toString method that returns the animal's
name, whether the animal is warm blooded, and a list of all animal
names that apply to the animal. The toString method can be in the
class directly or inherited. Animals that can be adopted as pets have
a method "getHomeCareInstructions" that returns a description of how
to care for the animal. Animals that live in water (are water
dwellers) have a method "livesOnLand" that returns a boolean of
whether the animal also can live on land. Animals that have wings have
a method "flies" that returns a boolean of whether the animal can fly.
This part of the assignment isn't necessarily difficult from a
programming perspective. What you should spend time on is carefully
considering the design of you classes and how they should be related
through inheritance or interfaces
I'm not sure how to design this because I know a bird is winged, but so is a bat. Therefor bat would extend winged, but bats are also mammals. I can't have winged extend mammal because birds are not mammals. Also, whales and otters are watter dwellers, but are also waterdwellers. I can't have waterdwellers extend mammals (because whales/otters are mammals), but fish are not mammals and are waterdwellers. How would I make it so a bat is both winged and a mammal? The programming is the easy part, just struggling with the structure of the project. How can I structure this so it could work?
So in your modelling you have to think:
Which are actual animals?
e.g. whales, otters -> classes
which are a type of animal?
e.g. a bird. -> abstract class
Since every emu is a bird.
This is called the Liskov Substitution Principle https://en.wikipedia.org/wiki/Liskov_substitution_principle
Which are characteristics of an animal?
e.g. WaterDweller, Winged -> those are interfaces.
Every class can have one superclass, it can have many characteristics, like being winged, or being a waterdweller, or adoptable
one addition for your bat example:
It is a mammal -> therefore it's superclass is mammal. It is winged - which is a characteristic - so it implements the winged interface.
class Bat extends Mammal implements Winged{
}
Related
This question isn't worded the best, but essentially I created some classes that can be used as types called Dog, Cat, Whale, etc. I also made another class that could take in a pet. How would I make classes like dog, cat, etc. belong to the pet type?
What you're looking for is called inheritance. In Java, you use the extends keyword in the class definition to make one class extend another.
For example:
public class Dog extends Pet { ...
In one of my projects, I have to implement the Factory design pattern to solve a specific issue.
I have one parent interface and two child interfaces. In the next stage, I have to create a factory which will return an instance of a specific class based on given input.
Please see my sample code below which explains my problem and the sample diagram as well.
Sample Diagram
Sample Code
enum AnimalType{ DOG, CAT }
Class Factory{
public Animal getInstance(AnimalType animalType){
Animal animal = null;
switch(animalType){
case DOG: animal = new Dog();
break;
case CAT: animal = new Cat();
break;
default:
break;
}
return animal;
}
}
/*Actual Problem */
Animal animal = Factory.getInstance(AnimalType.DOG);
/* When I use any IDE like IntellijIdea or Eclipse it only provides eat() method after animal and dot (ie. animal. ) */
animal.<SHOULD PROVIDE eat() and woof() from Dog> but it is only providing eat()
Any advice to overcome this problem? Or, should I consider any other Design Pattern for this problem?
Your problem is not directly related to the factory pattern. You are declaring an Animal and then want to treat it as a Dog. It doesn't matter how you create it you will need to make it a Dog to call doggy methods.
You have many options to resolve this. Here are a few alternatives.
Have separate methods for creating different extensions of Animal. So instead of Animal getInstance(AnimalType type) you would have Dog getDog() and Cat getCat() methods in the factory. Given the factory needs to be aware of all these classes anyway this seems like the best option to me.
Continue to return Animal instances from your factory but then use the 'visitor' pattern to treat dogs and cats differently.
Use instanceof and casting to treat animals as dogs or cats. This is not recommended for most situations but is suitable in some cases.
I think your problem is related to "General OO" not really about Factory design pattern. Now let's take a look at your three interfaces: Animal, Dog and Cat. The Dog and Cat are implemented the Animal interface, it does not mean that they have exactly the same behaviors with difference implementations, what we can make sure is they will respect the behaviors of Animal.
For instance:
The Dog and Cat will have the same behavior is eat()
The Dog has a woof() behavior which do not exist in the Cat
The Cat has a miaw() behavior which do not exist in the Dog
Therefore, when you implement the Simple Factory (according to Head Of Design Pattern it is not real design pattern, just a programming idiom) to deal with create object and return the Animal interface, it means you are considering the Dog and Cat as an Animal with the same behavior is eat(). That's why you can not do somethings like this in your code
/*Actual Problem */
Animal animal = Factory.getInstance(AnimalType.DOG);
/* When I use any IDE like IntellijIdea or Eclipse it only provides eat() method after animal and dot (ie. animal. ) */
animal.<SHOULD PROVIDE eat() and woof() from Dog> but it is only providing eat()
In my opinion, there are some possible implementations:
For simplicity, you can create 2 Simple Factory, one for Dog and other is Cat
If you know what you want, you can cast the Animal to Dog or Cat, and then use their functions
Implement the Abstract Factory pattern, it will provide and abstract interface for creating a family of product (Dog and Cat).
I hope it can help you.
Can a subclass also be a superclass of another subclass in Java? Perhaps this is not the best example, but consider the following classes:
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }
public class Siamese extends Cat { }
public class JackRussel extends Dog { }
Does inheritance allow for this sort of behaviour?
Given that JackRussels would require the methods and properties of both an Animal and a Dog, and Siamese's would require the methods and properties of both Animal and Cat.
If not, is there a generalised approach I could take to achieve this sort of behaviour?
Cheers
Yes, that behavior is exactly what is expected when using inheritance in Java.
Here's some quick reading that you may find usefull: http://www.homeandlearn.co.uk/java/java_inheritance.html
Your JackRussel object will inherit all fields and methods from it's Animal and Dog super-classes that are:
not declared private;
are not overridden (in which case will get only have access to the overridden one);
are not shadowed (in which case will get only have access to the shadowed one);
Here's another quick link on shadowing and overriding in Java:
http://docstore.mik.ua/orelly/java-ent/jnut/ch03_04.htm
Having those point in mind, you can easily design inheritance tree that can propagate parent’s behavior and state to all of its children.
Thanks.
Of course this is possible. But saying that the Siamese would require methods and fields from both superclasses is a bit wrong. When cat extends animal it gets all of the fields and methods of animal (if you do not override them). Then, when Siamese extends that cat class, it will automatically get the whole Cat class, including the things that are from the Animal class, regardless of whether they are overriden or not.
In short terms, this is possible.
Can I say that class House HAS-A class Animal even if that is not declared explicitly and can be seen only through inheritance?
public class Animal {}
public class Dog extends Animal {}
public class House {
private Dog inhabitant = new Dog();
}
Your class "House" Has-A Dog.
Every Dog Is-AN Animal.
So, Yes, your House has an Animal.
The is a relationship is expressed with inheritance and has a relationship is expressed with aggregation. Both inheritance and aggregation allow you to place sub-objects inside your new class.
Simple example:
Aggregation: is used when House has a Dog/Animal and Dog/Animal can exist without House.
It's more a question about semantics, there's nothing wrong in saying House has an Animal since Dog is an Animal
But reference 'inhabitant' in house can only point to a Dog instance. So, it's better to say House has a Dog. It will be more align with Law of Demeter.
You can't say that class House HAS-A class Animal. You could say an instance of class House has an instance of class Animal (or Dog).
One of the advantages of Object-Oriented programming language is code reuse. There are two ways we can do code reuse either by implementation of inheritance (IS-A relationship), or aggregation (HAS-A relationship). Although the compiler and Java virtual machine (JVM) will do a lot of work for you when you use inheritance, you can also get at the functionality of inheritance when you use composition.
Read Difference between IS-A and HAS-A relationships
I would say yes, because Animal is polymorphic for Dog
Yes, because the House class HAS-A Dog and Dog IS-A (extends)
Animal.....
Is-A means it refers to inheritance or implementation using extends or implements keywords.
Has-A means instance of one class “has a” reference to an instance of another class or another instance of same class without using any keywords.
Suppose I have two classes: Animal and Dog. Dog is a subclass of Animal. I do the following code:
Animal a = new Dog();
Now I can call methods of the Dog class through the a variable.
But my question is this: if I can call all of Animal's methods through the Dog objects (inheritance) than why should I use the polymorphism principle? I can just declare:
Dog d = new Dog();
With this declaration can use all of Animal's methods and Dog methods. So why use polymorphism? Thank you very much for your answer.
In Java, the concepts of polymorphism and inheritance are "welded together"; in general, it does not have to be that way:
Polymorphism lets you call methods of a class without knowing the exact type of the class
Inheritance lets derived classes share interfaces and code of their base classes
There are languages where inheritance is decoupled from polymorphism:
In C++ you can inherit a class without producing polymorphic behavior (i.e. do not mark functions in the base class with virtual)
In Objective C you can implement a method on an unrelated class, and call it from a place that knows only the signature of the method.
Going back to Java, the reason to use polymorphism is decoupling your code from the details of the implementation of its counter-parties: for example, if you can write a method Feed(Animal animal) that works for all sorts of animals, the method would remain applicable when you add more subclasses or implementations of the Animal. This is in contrast to a Feed(Dog dog) method, that would be tightly coupled to dogs.
As far as the
Dog d = new Dog();
declaration goes, there is no general reason to avoid this if you know that the rest of your method deals specifically with dogs. However, in many cases the later is not the case: for example, your class or your methods would often be insensitive to the exact implementation, for example
List<Integer> numbers = new ArrayList<Integer>();
In cases like that, you can replace new ArrayList<Integer>() with new LinkedList<Integer>(), and know that your code is going to compile. In contrast, had your numbers list been declared as ArrayList<Integer> numbers, such switchover may not have been a certainty.
This is called "programming to an interface". There is a very good answer on Stack Overflow explaining it.
You can have other implementations of the Animal class, such as Cat. Then you can say
Animal a = new Dog();
Animal b = new Cat();
You can call methods of the Animal class without caring which implementation it really is, and polymorphism will call the correct method. E.g.
a.speak(); // "Woof"
b.speak(); // "Meow"
Really, it's not "Polymorphism vs Inheritance" but "Polymorphism using Inheritance".
Polymorphism allows you to write a method that works for any Animal:
public void pet(Animal animal) {
...
}
This method would accept Dog, Cat, etc, including subclasses of Animal that are yet to be written.
If the method were to take Dog, it would not work for Cat etc.
If you are certain that it will always be a dog there is no reason for it. You might aswell use Dog d = new Dog(); as you described. But let's say you used a method instead of a constructor. The method returned an animal and you wouldn't know which implementation of animal you would get. You would still be able to use the same methods on the animal (even if it's a Dog, Elephant cat etc).
For extensibility purposes inheritance simplifies things. When you want to create an elephant or cat which also share some animal methods, You can easily get those by having animal as super class.
Normally the question you've asked is more similar to Inheritance vs Composition :) More "real life" example of why it's good to use polymorphism is for example usage of strategy design pattern. You can have many TaxPolicy implementation: UsaTaxPolicy, CanadaTaxPolicy, EuTaxPolicy, etc. If you have method calculateFinalPrice, which have to also calculate tax, then you inject the proper implementation and good calculation is executed, no matter you've passed Usa, Canada or Eu implementation.
inheritance is the dynamic polymorphism. I mean when you remove inheritance you can not override anymore.