Class design - manual cast alternatives - java

Question is related to classes below. Zookeeper1 and Zookeeper2 are 2 alternatives that I could use. I can potentially store in future different types of animals inside Zookeeper. I should be able to get those classes. In 1st case I store all animals in list (meaning in future I can add other new Animals easily), but I need to cast dog with (Dog) when I need to get it. Read somewhere that casts are code-smell, so I wanted to see if there are any alternatives? Other solution prevents casting, but has problem of adding new lists each time I add new animal.
class AnimalId{}
interface Animal{
AnimalId getAnimalId();
void breathe();
}
class Cat implements Animal{
public AnimalId getAnimalId() { return null; }
public void breathe() {}
}
class Dog implements Animal{
public AnimalId getAnimalId() { return null; }
public void breathe() {}
public void bark(){}
}
class ZooKeeper1{
Map<AnimalId, Animal> animals = new HashMap<>(); //future-proof
void addAnimal(Animal a){
animals.put(a.getAnimalId(), a);
}
void printAnimals(){
animals.forEach((key, value) -> System.out.println(key));
}
Dog getDog(AnimalId animalId){
return (Dog)animals.get(animalId); //NOK - must type-cast!
}
public static void main(String[] args) {
ZooKeeper1 zk1 = new ZooKeeper1();
zk1.addAnimal(new Cat());
zk1.addAnimal(new Dog());
zk1.printAnimals();
Dog d = zk1.getDog(new AnimalId());
d.bark();
}
}
class ZooKeeper2{
Map<AnimalId, Cat> cats = new HashMap<>();
Map<AnimalId, Dog> dogs = new HashMap<>(); //will need to add more lines in future
void addCat(Cat c){
cats.put(c.getAnimalId(), c);
}
void addDog(Dog d){
dogs.put(d.getAnimalId(), d); //will need to add more lines in future
}
void printAnimals(){
cats.forEach((key, value) -> System.out.println(key));
dogs.forEach((key, value) -> System.out.println(key)); //will need to add more lines in future
}
Dog getDog(AnimalId animalId){
return dogs.get(animalId); //OK no type-cast
}
public static void main(String[] args) {
ZooKeeper2 zk2 = new ZooKeeper2();
zk2.addCat(new Cat());
zk2.addDog(new Dog());
zk2.printAnimals();
Dog d = zk2.getDog(new AnimalId());
d.bark();
}
}

Imagine I wrote class ZooKeeper1 without any knowledge of class Dog and passed it on to you. You then decide to extend the class and add the method Dog getDog(AnimalId id).
Would you expect this to just work? If you see the gap in your reasoning, then you understand why casting is a bad idea.
Casting is a not a miracle solution. The only safe way to use it is to only cast objects of known types; for example, if you store a Dog instance in a variable of type Animal, then you know for sure that you can cast the result of getAnimal(..) to type Dog.

OK, so after looking into heterogeneous containers in Java, I guess this would be so far the best option I have? Any comments on this type of solution?
interface Animal { AnimalId getId(); }
class AnimalId { int id; AnimalId(int id){this.id = id;} public boolean equals(Object o){ return id==((AnimalId)o).id; } public int hashCode(){ return 1; } }
class Cat implements Animal { AnimalId id; Cat(AnimalId id){this.id=id;} public AnimalId getId(){ return id; } public String catSpecific(){ return "CS"; } }
class Dog implements Animal { AnimalId id; Dog(AnimalId id){this.id=id;} public AnimalId getId(){ return id; } public String dogSpecific(){ return "DS"; } }
class Zoo {
private Map<Class<? extends Animal>, Map<AnimalId, Animal>> animals = new HashMap<>();
public <T extends Animal> void assignAnimal(T animal){
animals.computeIfAbsent(animal.getClass(), k -> new HashMap<>()).put(animal.getId(), animal);
}
public <T extends Animal> T getAnimal(Class<T> type, AnimalId animalId){
return type.cast(animals.get(type).get(animalId));
}
public static void main(String[] args) {
Zoo zoo = new Zoo();
AnimalId animalId = new AnimalId(1);
Animal animal1 = new Cat(animalId);
Animal animal2 = new Dog(animalId);
zoo.assignAnimal(animal1);
zoo.assignAnimal(animal2);
Cat cat = zoo.getAnimal(Cat.class, animalId);
Dog dog = zoo.getAnimal(Dog.class, animalId);
System.out.println(cat.catSpecific());
System.out.println(dog.dogSpecific());
}
}

Related

do i have to use instanof in this problem? or how should i code instead?

i wrote an example code for my question. i want to use polimorfism and i try to change a variable by the type of object. This code is working but is it the best way of that? Should i use a common method in both classes to return the variable? Thanks
package example;
import java.util.Scanner;
class Animal{}
class Dog extends Animal{}
class Bird extends Animal{}
public class Example {
public static void main(String[] args) {
Animal a;
int leg=0;
Scanner k=new Scanner(System.in);
String s=k.next();
if(s.equals("dog")) a=new Dog();
else a=new Bird();
if(a instanceof Dog) leg+=4;
else if(a instanceof Bird) leg+=2;
System.out.println(leg);
}
}
You should place common functionality into the parent class Animal and implement specific functionality into child classes Bird and Dog.
abstract class Animal {
abstract int legs();
}
class Bird extends Animal {
#Override
int legs() {
return 2;
}
}
class Dog extends Animal {
#Override
int legs() {
return 4;
}
}
There's no need for instanceof, just call the legs method of Animal and the implementing class will output the correct value.
public class Example {
public static void main(String[] args) {
Animal animal;
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
if(s.equals("dog")) {
animal = new Dog();
} else {
animal = new Bird();
}
System.out.println(animal.legs());
}
}
Put the common attributes and behaviors to the parent
abstract class Animal {
public abstract int getLegs();
}
class Bird extends Animal {
#Override
public int getLegs() {
return 2;
}
}
class Dog extends Animal {
#Override
public int getLegs() {
return 4;
}
}
, Add a method that creates an object based on parameter this is Factory Design pattern factory_pattern.htm
public static void main(String[] args) {
Animal animal;
Scanner scanner = new Scanner(System.in);
String animalType = scanner.next();
animal = getAnimal(animalType);
if (animal != null)
System.out.println(animal.getLegs());
scanner.close();
}
static Animal getAnimal(String type) {
if(type==null || "".equals(type)) return null;
Animal animal;
if ("dog".equalsIgnoreCase(type)) {
animal = new Dog();
} else if("bird".equalsIgnoreCase(type){
animal = new Bird();
}
return animal;
}
The number of legs the animal has should be contained within the subclass of Animal rather than set from the outside as you've currently got. Something like:
public abstract class Animal {
protected int numLegs;
public int getNumLegs() {
return numLegs;
}
}
public class Dog extends Animal {
public Dog() {
numLegs = 4;
}
}
Good luck!

Superclass/Subclass methods [duplicate]

This question already has answers here:
why java polymorphism not work in my example
(3 answers)
Closed 6 years ago.
I have a situation
public class Animal
{
String noise;
public String makeNoise()
{
return noise;
}
}
Then there will be a subclass with the concrete definition of the noise.
public class Dog extends Animal{
String noise = "woof";
}
also
public class Cat extends Animal{
String noise = "meow";
}
What I want to do is
Animal cat = new Cat();
cat.makeNoise(); // This will be 'meow'
and
Animal dog = new Dog();
dog.makeNoise(); // This will be 'woof'
Basically, I don't want to repeat the makeNoise() method when I create an animal. However, this will not work. (Noise is an empty string)
I could use a static object like
static String NoiseDog = "woof"
static String NoiseCat = "meow"
but then again I have to write the makeNoise() method for each animal. Is there a better way to architect this?
If you want to force all sub-classes of Animal to have a noise defined, you can enforce that in the constructor:
public abstract class Animal {
private final String noise;
public Animal(final String noise) {
this.noise = noise;
}
public String makeNoise() {
return noise;
}
}
Then Dog:
public class Dog extends Animal {
public Dog() {
super("woof");
}
}
And Cat:
public class Cat extends Animal {
public Cat() {
super("meow");
}
}
And to test it out:
public class Test {
public static void main(String[] args) {
final Animal dog = new Dog();
System.out.println(dog.makeNoise());
final Animal cat = new Cat();
System.out.println(cat.makeNoise());
}
}
Output:
woof
meow
public class Cat extends Animal{
String noise = "meow";
}
This creates an instance variable named "noise" that hides the superclass variable.
Instead, you need this to set the superclass value:
public class Cat extends Animal{
public Cat() {
noise = "meow";
}
}
Make the Animal class abstract. This way, there can be no such thing as an Animal object which calls makeNoise.
Then, set the noise String to a value within the constructor of each subclass as appropriate to that animal's sound.
Alternatively, you could implement an interface like so:
Animal:
public interface Animal {
public String makeNoise();
}
Dog:
public class Dog implements Animal {
public String makeNoise() {
return "woof";
}
}
Cat:
public class Cat implements Animal {
public String makeNoise() {
return "meow";
}
}
Test:
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
System.out.println(dog.makeNoise());
Animal cat = new Cat();
System.out.println(cat.makeNoise());
}
}
Output:
woof
meow

Java. Get specific type using generics in enum

Here is some enum with get() method.
public class ZooTest {
public enum Animals {
CHLOE("cat"),
MOLLY("dog"),
LUNA("cat"),
TOBY("dog"),
ZOE("parrot"),
SNICKERS("cat");
private final String type;
Animals(String type) {
this.type = type;
}
public class Animal {
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
public class Parrot extends Animal {
}
public Animal get() {
return "cat".equals(type)
? new Cat()
: "dog".equals(type)
? new Dog()
: new Parrot();
}
}
#Test
public void shouldReturnSpecificClass() {
assertTrue(Animals.CHLOE.get() instanceof Cat);
}
#Test(expectedExceptions = {ClassCastException.class})
public void shouldReturnSpecificClass2() {
Dog dog = (Dog) Animals.CHLOE.get();
}
}
The question is how can it be improved to return specific type of animal without using type casting outside enum. Of course I can use methods like
public <T extends Animal> T get(Class<T> clazz) { return (T) get(); }
but maybe there is less clumsy way.
This answer is based on assumption that you don't actually need separate instances of Cat for CHLOE, LUNA, or SNICKERS. Also since your Animals didn't have any methods or state it doesn't look like you really need them as separate classes. So maybe something like this will be easier:
public enum AnimalType {
Cat, Dog, Parrot;
}
public enum Animals {
CHLOE(AnimalType.Cat),
MOLLY(AnimalType.Dog),
LUNA(AnimalType.Cat),
TOBY(AnimalType.Dog),
ZOE(AnimalType.Parrot),
SNICKERS(AnimalType.Cat);
private final AnimalType type;
Animals(AnimalType type) {
this.type = type;
}
public AnimalType get() {
return type;
}
}
You can create an abstract method get that and each instance of Animals has to implement:
public enum Animals {
CHLOE("cat") {
#Override
public Animal get() { return new Cat(); }
},
MOLLY("dog") {
#Override
public Animal get() { return new Dog(); }
}
//... and so on
public abstract Animal get();
}
You have two mistakes of enum using. The first enum entities must provided something like type not instance (how it pointed Quirliom), and then your Animal enum must contains members cat, dog etc. The second unfortunately you can not extend any class from enum.

In an ArrayList of Object, how can I convert Object into one of 3 instance of classes contained in an ArrayList?

I'm doing a simple Zoo application to understand oriented object concepts in Java.
My model is as follow:
1) A Zoo has a number of Cages
2) A Cage has a a mixture of Feline, Primate or Bird
3) An Animal can eat, sleep or drink
4) Feline extends Animal (Do extra Feline stuff)
5) Primate extends Animal (Do extra Primate stuff)
6) Bird extends Animal (Do extra Bird stuff)
The problem:
While it's pretty easy to handle x number of cages in a zoo (ArrayList of Cage), I'm struggling with the Animals in Cage.
I found out that I need to have an ArrayList of Object.
So far so good, but when I try to obtain my animal back and have him scratch a post, it's not a Feline anymore, it's an Object.
public class Cage{
private String name;
private ArrayList<Object> animals = new ArrayList<Object>();
public Cage(String name){
this.name = name;
}
public void addFeline(String name){
Feline newFeline= new Feline(name);
this.animals.add(newFeline);
}
public void addPrimate(String name){
Primate newPrimate= new Primate(name);
this.animals.add(newPrimate);
}
public void addBird(String name){
Bird newBird= new Bird(name);
this.animals.add(newBird);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Object getAnimal(int index){
Object myAnimal = this.animals.get(index);
return myAnimal;
}
}
And the way I call it:
Zoo myZoo = new Zoo("My Zoo");
myZoo.addCage("Monkey Exhibit");
Cage myCage = myZoo.getCage(0);
myCage.addFeline("Leo");
Object MyAnimal = myCage.getAnimal(0);
The Question: How can I turn Object back into instance of class Feline so it can Scratch a Post?
I think the best way to approach this problem would be using the Strategy design pattern.
Feline, Primate and Bird should implement an interface Animal. The Cage would then have a method public void addAnimal(Animal animal);
The object creation for Feline, Primate and Bird should be outside of Cage.
I have put together some code if this can help. I would design the application similar to something below.
Behaviours should be encapsulated using interfaces. e.g. EatingBehaviour
public interface Animal {
public String getName();
}
public interface EatingBehaviour {
public void howManyTimes();
}
public class RealLionEatingBehaviour implements EatingBehaviour{
#Override
public void howManyTimes() {
System.out.println("I eat once a day");
}
}
public class ToyLionEatingBehaviour implements EatingBehaviour {
#Override
public void howManyTimes() {
System.out.println("I never eat! I am a toy lion.");
}
}
public abstract class Feline implements Animal{
public abstract void scratchPost();
private EatingBehaviour eatingBehaviour;
public EatingBehaviour getEatingBehaviour() {
return eatingBehaviour;
}
public void setEatingBehaviour(EatingBehaviour eatingBehaviour) {
this.eatingBehaviour = eatingBehaviour;
}
}
public class Lion extends Feline {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
Lion (String name) {
this.name=name;
}
public void scratchPost(){
System.out.println(getName() + " Lion Scratching Post!");
}
}
public class AnimalFactory {
public static Animal getAnimalInstance(String type, String name){
Animal animal=null;
if ("lion".equalsIgnoreCase(type)) {
animal = new Lion(name);
}
return animal;
}
}
import java.util.ArrayList;
import java.util.List;
public class Cage {
private List<Animal> animals = new ArrayList<Animal>();
public void addAnimal(Animal animal) {
animals.add(animal);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Animal getAnimal(int index){
return this.animals.get(index);
}
}
public class Zoo {
public static void main(String args[]) {
Cage cage = new Cage();
Animal animal = null;
animal = AnimalFactory.getAnimalInstance("Lion", "Sweety");
cage.addAnimal(animal);
Animal animalFromCage = cage.getAnimal(0);
if (animalFromCage instanceof Feline) {
Feline feline = (Feline) animalFromCage;
feline.setEatingBehaviour(new RealLionEatingBehaviour());
feline.scratchPost();
feline.getEatingBehaviour().howManyTimes();
feline.setEatingBehaviour(new ToyLionEatingBehaviour());
feline.getEatingBehaviour().howManyTimes();
}
}
}
Use a cast:
Object myAnimal = myCage.getAnimal(0);
Feline f = (Feline) myAnimal;
private List<Animal> animals = new ArrayList<Animal>();
public void findAnimal(int index) {
Animal myAnimal = animals.get(index);
if (myAnimal instanceof Feline) {
Feline feline = (Feline) myAnimal;
//do the work with Feline
} else if (myAnimal instanceof Primate) {
//do the work with Primate
}
// continue with the other types.
}
this will avoid a unexpected classcast exception. Since you know the type use the super type (Animal) in the Arraylist instead fo Object. if it is Obejct you can add anything to the List.
You should use an ArrayList<? extends Animal> instead of ArrayList<Object>. You would then cast a return value to the appropriate subclass of Animal.

Method chaining + inheritance don’t play well together?

This question has been asked in a C++ context but I'm curious about Java. The concerns about virtual methods don't apply (I think), but if you have this situation:
abstract class Pet
{
private String name;
public Pet setName(String name) { this.name = name; return this; }
}
class Cat extends Pet
{
public Cat catchMice() {
System.out.println("I caught a mouse!");
return this;
}
}
class Dog extends Pet
{
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return this;
}
}
class Bird extends Pet
{
public Bird layEgg() {
...
return this;
}
}
{
Cat c = new Cat();
c.setName("Morris").catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee(); // error! setName returns Pet, not Dog
Bird b = new Bird();
b.setName("Tweety").layEgg(); // error! setName returns Pet, not Bird
}
In this sort of class hierarchy, is there any way to return this in a way that doesn't (effectively) upcast the the object type?
If you want to avoid unchecked cast warnings from your compiler (and don't want to #SuppressWarnings("unchecked")), then you need to do a little more:
First of all, your definition of Pet must be self-referential, because Pet is always a generic type:
abstract class Pet <T extends Pet<T>>
Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:
The "getThis" trick provides a way to
recover the exact type of the this
reference.
This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).
The resulting code is:
public class TestClass {
static abstract class Pet <T extends Pet<T>> {
private String name;
protected abstract T getThis();
public T setName(String name) {
this.name = name;
return getThis(); }
}
static class Cat extends Pet<Cat> {
#Override protected Cat getThis() { return this; }
public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}
static class Dog extends Pet<Dog> {
#Override protected Dog getThis() { return this; }
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}
public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}
How about this old trick:
abstract class Pet<T extends Pet>
{
private String name;
public T setName(String name) { this.name = name; return (T) this; }
}
class Cat extends Pet<Cat>
{
/* ... */
}
class Dog extends Pet<Dog>
{
/* ... */
}
No, not really. You could work around it by using covariant return types (thanks to McDowell for the correct name):
#Override
public Cat setName(String name) {
super.setName(name);
return this;
}
(Covariant return types are only in Java 5 and above, if that's a concern for you.)
It's a bit convoluted, but you can do this with generics:
abstract class Pet< T extends Pet > {
private String name;
public T setName( String name ) {
this.name = name;
return (T)this;
}
public static class Cat extends Pet< Cat > {
public Cat catchMice() {
System.out.println( "I caught a mouse!" );
return this;
}
}
public static class Dog extends Pet< Dog > {
public Dog catchFrisbee() {
System.out.println( "I caught a frisbee!" );
return this;
}
}
public static void main (String[] args){
Cat c = new Cat();
c.setName( "Morris" ).catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName( "Snoopy" ).catchFrisbee(); // error! setName returns Pet, not Dog
}
}
public class Pet<AnimalType extends Pet> {
private String name;
public AnimalType setName(String name) {
this.name = name; return (AnimalType)this;
}
}
and
public class Cat extends Pet<Cat> {
public Cat catchMice() {return this;}
public static void main(String[] args) {
Cat c = new Cat().setName("bob").catchMice();
}
}

Categories

Resources