Class Design issues - java

Currently, I have the following class design :
AnimalHandler (A base class for all animals)
TigerHandler extends AnimalHandler, LionHandler extends AnimalHandler, LeopardHandler extends AnimalHandler and so on.
TigerHandler, LionHandler, LeopardHandler etc "HAS A" Tiger, Lion, Leopard and so on.
Now the issue is : TigerHandler, LionHandler, LeopardHandler etc are all the same(they have the same methods, etc) except that they deal with Tiger,Lion, Leopard, etc classes respectively. So if I need a new Animal group called Cheetah, I just need to copy any of the (Tiger|Lion|Leopard)Handler and do a search and replace of its "HAS A" class names like Tiger,Lion, Leopard.
Instead of copying/creating a new CheetahHandler as above, is there a way (design) that I can use ? Like, say, a GenericHandler that can deal with any of these "HAS A" classes (like Tiger,Lion, Cheetah, etc).

If all your handlers do is provide type safety, and does nothing else, you can use generics instead:
public class AnimalHandler<T extends Animal> {
private T theAnimal;
public T getTheAnimal() {}
// Etc
}

Using generics is a much better approach.
Make sure all animal classes (Tiger, Lion, Leopard) extends lets say an Animal class.
Then use:
public class AnimalHandler<A extends Animal> {
private A animal;
}
And use animal inside your code.
When you want to instantiate a tiger handler, use it as:
AnimalHandler<Tiger> tigerHandler = new AnimalHandler<>();

A bit of details in terms of how each of Tiger,Lion, Leopard classes are used in each of the handler
-- If the method interfaces are all the same, and only internal functionality is different
-- if there is extension on Animalhandler you are doing inside the childHandlers
Then, then you should make AnimalHandler an abstract class (implementing iAnimalHandler) and use generics to process the Animal (Super class for each Tiger,Lion, Leopard )

As others have noted, generics are a great approach, or you could use a Strategy pattern:
class Animalhandler {
List<Animal> animals;
// add, remove and do stuff with animals
}
interface Animal {
void makeSound();
}
class Cat extends Animal {
public void makeSound() {
// meow
}
}

Related

Java Generic method takes a parameter of the class's type

I have the following code:
public class Animal {
public <T extends Animal> void doSomething(T instance) {
//do stuff
}
}
but the parameter to the method should be of the same type as the class it's being called on. E.g. this is valid:
public class Dog extends Animal {}
public class Cat extends Animal {}
Dog dog1 = new Dog();
Dog anotherDog = new Dog();
dog1.doSomething(anotherDog);
But this is NOT valid:
dog1.doSomething(new Cat());
Is there any way to achieve this without implementing the method on all the subclasses? Do don't want to do that because there are a lot of subclasses and it would be too repetitive.
Generics serve to link things together. They tell the compiler that relationships exist between 2 different places that types occur. However, in your signature, T occurs only once: As parameter. This is useless. Why not just write void doSomething(Animal instance)? Your code is just a more complicated, and less flexible way of writing that. After all, any animal, even an instance of a subclass of animal, is an animal. There is nothing you can pass to the method <T extends Animal> void doSomething(T animal) that you cannot pass to void doSomething(Animal animal)!
What you want is both not possible and non-sensical. Imagine it was possible to tell java that the parameter of doSomething must be of the same type as the receiver of doSomething, then, consider this code:
Dog dog = new Dog();
Cat cat = new Cat();
Animal dogA = dog; // dogA and dog are pointing at the exact same object!
Animal catA = cat; // dogA and dog are pointing at the exact same object!
dogA.doSomething(catA); // so this would compile and run, then.
Look at that last line. No amount of type-based insistence that 'the parameter must be of the same type as the receiver' you care to add to java can ever make the compiler refuse to compile this code. And yet there is no difference between that and dog.doSomething(cat), because dog and dogA as well as cat and catA are referring to the same object.
And yet, that is evidently what you want. Thus, what you want is not a sensible thing to want.
There are things you can do, but this almost always leads to more problems. You have to generify your own type:
public class Animal<S extends Animal<S>> {
public void doToSibling(S other) {}
}
But this requires you to declare: class Dog extends Animal<Dog>, and there is nothing actually stopping you from class Dog extends Animal<Cat>. The S is not so much 'self type' as 'the thing I can do doToSibling to'.
I don't think there is an implicit way to reference to an overriding class.
You can declare the reqired subtype as generic argument on animal itself to have the described effect.
public class Animal<T extends Animal<?>> {
public void doSomething(final T instance) {
//do stuff
}
}
public class Dog extends Animal<Dog> {}
public class Cat extends Animal<Cat> {}
That beeing said, in practice it is hard to imagine where you want to go from here. What could a method contain that only two dogs can do but two different animals can't but also can be implemented with the same code?
This is often the point where you want to overthink if a common abstract base-class really is helpful in the long run. If the implementation code turns out to be different for all the animals, maybe a common interface on independent classes might be the better option.

The behavior of the "this" keyword in abstract classes and generics

Consider the following classes
Reinventing the wheel as far as serialization goes, I know:
abstract class AnimalSerializer<E extends Animal> {
/**
* The type E (which extends Animal) is important here.
* I want to be able to write data that is specific to a subclass of an animal.
*/
abstract void writeAnimal(E animal);
abstract Animal readAnimal();
}
abstract class Animal {
AnimalSerializer<? extends Animal> serializer;
Animal(AnimalSerializer<? extends Animal> speciesSerializer) {
serializer = speciesSerializer;
}
void writeAnimalToFile() {
// This line fails to compile
serializer.writeAnimal(this);
}
}
These classes demonstrate the use of this pattern:
class DogSerializer extends AnimalSerializer<Dog> {
#Override
void writeAnimal(Dog animal) {
// Write the stuff that is specific to the dog
// ...
}
#Override
Animal readAnimal() {
// Read the stuff specific to the dog, instantiate it, and cast it as an animal.
// ...
return null;
}
}
class Dog extends Animal {
String dogTag = "Data specific to dog.";
Dog() {
super(new DogSerializer());
}
}
My question pertains to the line that failed to compile (serializer.writeAnimal(this)). I had to pull up the language specification for the first time to learn more about the this keyword, but I think the issue is that the "this" keyword is of the type Animal, and the bounded wildcard generic <? extends Animal> only supports types that are subclasses of Animal, not the Animal type itself.
I would argue that the compiler should know that the type of the this keyword must be an object that extends Animal, given that Animal cannot be instantiated, and the this keyword is only applicable to objects that have been.
Is there a reason why the compiler cannot know this? My guess is that there is a case that explains why the this keyword cannot be guaranteed to be a subclass of Animal.
Furthermore, is this pattern fundamentally flawed as a result?
Your serializer generic type is ? extends Animal. Your this type is Animal, which also can be considered as ? extends Animal. But these two ? are different types. There is no constraint to let the compiler know they are same type.
For example, I write a Cat class
class Cat extends Animal {
Cat(){
super(new DogSerializer()); // this is ok for your generic
}
}
This is why the compiler gives you an error.
In addition to what Dean said:
You can make Animal generic: Animal<S extends Animal>
Then the serializer becomes AnimalSerializer<S> serializer. Now it references a "known" subclass of Animal.
And the extends becomes Dog extends Animal<Dog>. Unfortunately, there is no way to prevent Cat extends Animal<Dog>.
You still have to cast in the offending line: serializer.writeAnimal((S)this);
But now it is possible to do that because you know what class to cast to.
This is the downside of ? in generics.

When to use or how to use Multiple Bound in generics

I am new to generics and learning generics from hear
https://docs.oracle.com/javase/tutorial/java/generics/bounded.html
I am learning about Multiple Bounds
what I understood is you can specify class like follows
class D <T extends A & B & C> { /* ... */ }
D<A> d = new D<>();
only if A does implements B and C both
other wise compile time error will ocur
also B and C should be Interface other wise //interface is expeced compile time error will occurs
I am not talking about wildcards
My problem is I am not getting any real programing use of this.
I am finding a way/example how can i use Multiple bound generics while codding.
When should I use it?
thanks
Consider the following snippets:
class SpineWarmCollection <T extends Vertebrate & Warmblooded> { /* ... */ }
class Mammal extends Vertebrate implements Warmblooded {}
class Bird extends Vertebrate implements Warmblooded {}
class Reptile extends Vertebrate {}
SpineWarmCollection<Mammal> mammalCollection = new SpineWarmCollection<>();
SpineWarmCollection<Bird> birdCollection = new SpineWarmCollection<>();
SpineWarmCollection<Reptile> reptileCollection = new SpineWarmCollection<>(); // Generates a compile error, since Reptiles are not warmblooded.
Vertebrate is a class in animal taxonomy; however, warmbloodedness is a trait. There's no single ancestor class for warmblooded-ness, since both Mammals and Birds are warmblooded, but their common ancestor, Vertebrate, is not.
Since T can only be a class that extends Vertebrate and Warmblooded, the generic can access any methods declared in Vertebrate and Warmblooded.
You don't even need a class. T could extend interfaces only, which would allow a generic to be used by any sets of classes that implement the interfaces, even of those sets of classes are completely unrelated to one another.

Why different types of object reference is allowed in Java?

I wonder why it is allowed to have different type of object reference?
For example;
Animal cow = new Cow();
Can you please give an example where it is useful to use different type of object reference?
Edit:Cow extends Animal
This is at the heart of polymorphism and abstraction. For example, it means that I can write:
public void handleData(InputStream input) {
...
}
... and handle any kind of input stream, whether that's from a file, network, in-memory etc. Or likewise, if you've got a List<String>, you can ask for element 0 of it regardless of the implementation, etc.
The ability to treat an instance of a subclass as an instance of a superclass is called Liskov's Substitution Principle. It allows for loose coupling and code reuse.
Also read the Polymorphism part of the Java tutorial for more information.
On a simpler note, this enables polymorphism. For example you can have several objects that derive from Animal and all are handle similar.
You could have something like:
Animal[] myAnimal = {new Cow(), new Dog(), new Cat()};
foreach (Animal animal in myAnimal)
animal.Feed();
The Feed() method must then be overriden within each child class.
By the way, code is C#-like but concept is the same in Java.
This is basically a concept of standardization.
We know that each animal have some common features. Let us take an example of eating and sleeping, but each animal can have different way of eating or sleeping ... then we can define
public abstract class Animal
{
public abstract void Eat();
public abstract void Sleep();
}
//Now Define them in various classes..
public class Cow extends Animal
{
pubic void Eat()
{
//process of eating grass
}
public void Sleep()
{
//process of sleeping
}
}
public class Lion extends Animal
{
public void Eat()
{
//process of eating flesh
}
public void Sleep()
{
//process of sleep
}
}
Now you do not have to define different objects to different classes... just use Animal and call generally
public class MyClass
{
public static void main(String[] args)
{
Animal _animal = new //think the type of animal is coming dynamically
//you can simply call
_animal.Eat();
_animal.Sleep();
// irrespective of checking that what can be the animal type, it also reduces many if else
}
}
This is called polymorphism and it's one of the most powerful aspects of Java.
Polymorphism allows you to treat different objects the same.
It's a great way to create re-usable, flexible code.
Unfortunately it's a part of Java that new programmers often take awhile to understand.
The example you've provided involves inheritance (extending a class).
Another way to enjoy the benefits of polymorphism is to use interfaces.
Different classes that implement the same interface can be treated the same:
class Dog extends Animal implements Talker {
public void speak() {
System.out.println("Woof woof");
}
}
class Programmer implements Talker {
public void speak() {
System.out.println("Polymorphism rocks!");
}
}
interface Talker {
public void speak();
}
public static void testIt() {
List<Talker> talkerList = new ArrayList<Talker>();
talkerList.add(new Dog());
talkerList.add(new Programmer());
for (Talker t : talkerList) {
t.speak();
}
}
Simply putting all Cows are Animals. So JAVA understands that when Cow extends Animal, a Cow can also be called as Animal.
This is Polymorphism as others have pointed out. You can extend Animal with Dog and say that Dog is also an Animal.
In another class/method you might want to use different implementations of the same interface. Following your example, you might have something like:
public void feed( Animal animal ) {
animal.getHome().insertFood(animal.getFavFood());
}
Now you can implement the details in your animal classes and don't have to extend this method anytime you add a new animal to your programm.
So in some cases you need the common interface in order not to implement a method for each implementation, whereas on other occasions, you will need to use the explicit implementation.
This is an inheritance 101 question.
It allows objects that share common functionality to be treated alike.
It also allows specific implementations to be supplied at runtime that are subclasses of an abstract type.
I could probably ramble on for ages. Perhaps thus question is just too broad to answer here.

Is co-variance safe here?

class Food{}
class Meat extends Food{}
class Animal{
void feed(Food f){}
}
class Lion extends Animal{
void feed(Meat m){}
}
void foo(Animal a){
Food f = new Food();
a.feed(f);
}
What will happen if we send to foo(new Lion()) ?
I know that it will get error but I need the explanation please
Your Lion can eat Meat, but it can also eat any kind of food (like Spinach).
If your Lion could not eat any kind of Food, then it could not be considered an implementation of Animal.
This is critical to understand when deciding to use sub-classing and class inheritance as a means of constructing programs: you don't make your subclasses more specific than your interface or super classes.
For sub-classing to work in ways that solve problems (instead of create problems), you need to abide by this guideline: All subclasses must be functionally equivalent to the super-class (Liskov Substitution Principle) This means that three classes which provide database access to three different databases is a good candidate for being subclasses from a common class (or perhaps sharing a common interface), because the "functionality" is "offer database access".
Where your Lion example falls short is that according to your definition of Animal a real world, Lions are not an Animals because real world Lions don't eat any kind of Food. Real world Lions are more specific in their food eating ability than the general definition of an unknown animal. And it is this functional difference which makes modeling real world Lions as subclasses of this specific definition of Animal a bad fit.
You could easily fix this by having the Animal "eat food" method throw an IncompatibleFoodException, which changes the definition of an Animal from something that "eats food" to something that "eats or rejects food".
This violates the Liskov substitution principle, so it should likely be avoided (as Edwin says, it's really not an Animal if it can't eat Food).
Perhaps against first thought, this will actually not result in an error, but rather will call Animal::feed instead of Lion::feed as expected.
Just reread the title, and to answer the question specifically: No, covariance is not safe here (in terms of behaviour. In terms of syntax it is.).
Quick copy and paste of the question into an example:
class Food{}
class Meat extends Food{}
class Animal{
void feed(Food f){
System.out.println("om nom nom");
}
}
class Lion extends Animal{
void feed(Meat m)
{
System.out.println("OM NOM NOM");
}
}
public class test
{
public static void main(String[] args)
{
foo(new Lion());
}
static void foo(Animal a){
Food f = new Food();
a.feed(f);
}
}
Outputs "om nom nom"

Categories