it may looks like a dummy question for you but I have difficulties solving this:
We have an abstract class Animal and Cat and Dog that extends it. In Animal we have a method produceSound(); that is abstract. As you can probably guess for Cat it should return "Mao" and for Dog - "Bao" or something like that. This is OK but now we must write a static method in the Animal class that returns Cat or Dog objects depending on their sound. For example: identifyAnimal("Mao") should return Cat.
Question: How to implement the identifyAnimal(String sound) method?
Here is some simple example of the hierarchy:
Animal class
public abstract class Animal {
protected abstract String produceSound();
protected static void identifyAnimal(String animalSound) {
// TODO
}
}
Cat class
public class Cat extends Animal{
#Override
protected String produceSound() {
return "Mao";
}
}
Dog class
public class Dog extends Animal{
#Override
protected String produceSound() {
return "Bao";
}
}
Test class
public class AnimalTest {
public static void main(String[] args) {
Animal.identifyAnimal("Bao");
}
}
In the AnimalTest class when calling the Animal.identifyAnimal("Bao"); we should get a Dog.
private static Class[] animalTypes = [Dog.class, Cat.class];
public static String identifyAnimal(String animalSound)
{
for (int i = 0; i < animalTypes.length; i++) {
Animal a = animalTypes[i].newInstance();
String s = a.produceSound();
if (animalSound.equals(s))
return animalTypes[i].getName();
}
return null;
}
So here a (terrible) way to do this. I actually twitched a little.
I don't know what language you are using, so I'm going with c++(sorry current mode) though you could replace maps with Dictionaries if we are in C#, whatever. This is a bad way to go about things, but should work(conceptually, anyway)
Again...Terrible...
public abstract class Animal {
protected abstract String produceSound();
protected static map<string, string> SoundList;
protected static bool registerSound(string sound, string type)
{
return (SoundList.insert( pair<string, string>(sound, type)))->second;//true if worked false if already there
}
protected static string identifyAnimal(string animalSound)
{
map<string,string>::iterator result = SoundList.find(sound);
if(result != SoundList.end())
return result->second;
else
return "What The Hell Is This!?";
}
}
Cat class
public class Cat extends Animal
{
Cat()
{
Animal::registerSound("Mao","Cat");
}
#Override
protected String produceSound() {
return "Mao";
}
}
abstract class Animal {
static Map<String,String> map = new HashMap<String,String>();
public Animal(String value) { map.put(produceSound(), value); }
protected abstract String produceSound();
protected static void identifyAnimal(String animalSound) {
System.out.println(map.get(animalSound));
}
}
class Cat extends Animal {
#Override
protected String produceSound() { return "Mao"; }
Cat(){ super("CAT"); }
}
class Dog extends Animal {
#Override
protected String produceSound() { return "Bao"; }
Dog(){ super("DOG"); }
}
class Test {
public static void main(String[] args) {
new Dog();
new Cat();
Animal.identifyAnimal("Bao");
}
}
Do a switch with the predefined sounds that you have and let each sound return a string with the name of the animal. For example "Mao" returns a string "Cat" and so on.
One more thing let ur identifyAnimal method returna string instead of void.
You could use reflection to get a list of all types that extend Animal, loop through them using Activator to create instances of each type running produceSound on each until you find the return value that matches animalSound, returning that instance. Slow, but effective if you want to avoid your Animal class being aware of what extends it.
What is the nature of the problem you are trying to solve? There is no 'right' way that is independent of the problem.
What does the consuming application need from the class Animal? What does your application need to do with the classes that it consumes? Nothing can be assumed unless these presumptions are clear.
Related
I have some related classes that implement the same method
class Dog {
public void speak() { System.out.println("Bark") }
}
class Cat {
public void speak() { System.out.println("Meow") }
}
90% of the time, users would want both the dog and the cat to speak. They don't want to know the details. When we add a new animal, they'll want it to speak too. The idea is to avoid:
// All animals need to be explicitly told to speak every time
new Dog().speak();
new Cat().speak();
// But we just added Birds, and the users need to remember to add this call everywhere
new Bird.speak();
I could do something like
class Animals {
public void speak() {
new Dog().speak();
new Cat().speak();
new Bird().speak();
}
}
So that users can just call new Animals().speak() every time.
However, 10% of the time, it does need to be configurable. What I want is a way for users to do something like this
// Used most of the time
Animals.withAllAnimals().speak();
// Sometimes they don't want cats, and they want the dogs to woof instead
Animals.exclude(Cat)
.configure(Dog.sound, "Woof")
.speak();
How can I structure my classes to accomplish this?
I know that it is question tagged with java. However, let me show an example with C# as these languages have many common things.
The first thing is I would use inheritance and create abstract class Animal as common behaviour Speak() is used. So, abstract class should define behavior, and the derived classes should implement that behavior:
public abstract class Animal
{
public abstract void Speak();
}
Then just use inheritance and override behaviour in derived classes:
public class Bird : Animal
{
public override void Speak()
{
System.Console.WriteLine("I am a bird!");
}
}
public class Cat : Animal
{
public override void Speak()
{
System.Console.WriteLine("I am a cat!");
}
}
public class Dog : Animal
{
public override void Speak()
{
System.Console.WriteLine("I am a dog!");
}
}
Then we need a class that allows to speak for all animals. Let's create Choir class for this purpose:
public class Choir
{
private List<Animal> choristers;
public void AddChoristers(IEnumerable<Animal> choristers)
{
if (choristers == null)
choristers = new List<Animal>();
choristers.AddRange(choristers);
}
public void SpeakAll()
{
foreach (Animal animal in choristers)
animal.Speak();
}
public void Speak(Func<Animal, bool> filter)
{
IEnumerable<Animal> filteredAnimals = choristers
.Where(filter ?? (animal => true));
foreach (Animal animal in filteredAnimals)
animal.Speak();
}
}
Pay attention to Speak() method. It can take a predicate as a parameter, so you can choose desired animals to speak().
Here are some ideas.
import java.util.*;
import java.util.function.Consumer;
/**
* An animal can either speak with its own voice, or another supplied
*/
interface Animal {
String speak();
String speak(String voice);
}
/**
* Base class for animal implementations.
*
* An animal is added to a Menagerie when created.
*/
abstract class BaseAnimal implements Animal {
private final String defaultVoice;
public BaseAnimal(Menagerie menagerie, String defaultVoice) {
this.defaultVoice = defaultVoice;
menagerie.add(this);
}
public String speak(String voice) {
return voice;
}
public String speak() {
return speak(defaultVoice);
}
}
/**
* A Dog. Even when given a voice the dog does things slightly differently.
*/
class Dog extends BaseAnimal {
public Dog(Menagerie menagerie) {
super(menagerie, "Bark!");
}
public String speak(String voice) {
return voice + " (and drools)";
}
}
/**
* A collection of animals. We can do something side-effectful to each, or create a new collection where
* some classes of animal are excluded or have different behaviour.
*/
interface Animals {
void forEach(Consumer<Animal> action);
Animals exclude(Class<Animal> clazz);
Animals configureVoice(Class<Animal> clazz, String voice);
}
/**
* An Animals instance which can contain only a single animal of each class
* (an arbitrary decision based on the code in the question)
*/
class Menagerie implements Animals {
Map<Class<? extends Animal>,Animal> animals = new HashMap<>();
public Menagerie() {
}
public Menagerie(Map<Class<? extends Animal>, Animal> animals) {
this.animals = new HashMap<>(animals);
}
public void add(Animal animal) {
animals.put(animal.getClass(), animal);
}
public void forEach(Consumer<Animal> action) {
animals.values().forEach(action);
}
#Override
public Animals exclude(Class<Animal> clazz) {
Menagerie m = new Menagerie(animals);
m.animals.remove(clazz);
return m;
}
/**
* Return an Animals instance which contains a proxy for a particular type of animal
* which will behave differently when speak() is called.
*/
#Override
public Animals configureVoice(Class<Animal> clazz, String voice) {
Menagerie m = new Menagerie(animals);
Animal a = m.animals.get(clazz);
if (a != null) {
m.animals.put(clazz, new Animal() {
#Override
public String speak() {
return voice;
}
#Override
public String speak(String voice) {
return a.speak(voice);
}
});
}
return m;
}
}
I have abstract class Pet with abstract method feed(...). The method must take only on of certain three types of food (DRY, WET or RAW). These can be String type as I use them only as indicators in SWITCH in later logic. Also I have two subclasses Cat and Dog. They implement the feed(...) method from Pet. The closest I came to, is using ENUM:
Pet.java:
public abstract class Pet {
public enum FoodType {
DRY,
WET,
RAW;
}
public abstract void feed(FoodType foodType);
}
Cat.java:
public class Cat extends Pet {
public void feed(FoodType foodType) {
switch (foodType) {
case DRY:
System.out.println("Feeding this cat dry food.");
break;
case RAW:
System.out.println("Feeding this cat raw food.");
break;
case WET:
System.out.println("Feeding this cat wet food.");
break;
}
}
}
Dog.java:
public class Dog extends Pet {
public void feed(FoodType foodType) {
// implementation similar to feed() in Cat.
}
}
App.java:
import pets.Dog;
import pets.Pet;
public class App {
public static void main(String[] args) {
Dog dog01 = new Dog();
dog01.feed(Pet.FoodType.DRY);
}
}
But I don't like that, since ENUMS are static by default FoodType can be accessed from anywhere in project. Without creating a Cat or Dog object, i can call Pet.FoodType.DRY from anywhere. Preferebly it should be associated only with an object that inherits from Pet, eg:
Dog dog01 = new Dog();
dog01.FoodType.DRY; // do smth with this
This is happening because you have declared FoodType as public. Please replace that with protected and this issue will be resolved.
protected enum FoodType
Alternatively to resolve this issue probably we can implement that as business logic
public abstract class Pet {
protected String[] foodType = new String[]{"RAW","DRY","WET"};
protected final String RAW_FOOD_TYPE = "RAW";
protected final String DRY_FOOD_TYPE = "DRY";
protected final String WET_FOOD_TYPE = "WET";
public abstract void feed(String foodType);
public String getRawFoodType()
{
return RAW_FOOD_TYPE;
}
public String getDryFoodType()
{
return DRY_FOOD_TYPE;
}
public String getWetFoodType()
{
return WET_FOOD_TYPE;
}
}
public class Cat extends Pet {
public void feed(String foodType)
{
if(foodType.equals(DRY_FOOD_TYPE))
{
System.out.println("Feeding this cat dry food.");
}
else if(foodType.equals(RAW_FOOD_TYPE))
{
System.out.println("Feeding this cat raw food.");
}
else if(foodType.equals(WET_FOOD_TYPE))
{
System.out.println("Feeding this cat wet food.");
}
else
{
throw new RuntimeException("Invalid foodtype");
}
}
}
public class App {
public static void main(String[] args) {
Cat cat01 = new Cat();
cat01.feed(cat01.getDryFoodType());
}
}
```
So usally it should be fine to have public enum in practise for this. But to answer your question yes it is possible by modifying the structure a bit. So the constants here could be as enum or as private final string both would be fine.
Taking this case for enum, declare it as protected. Then create a method which will return the enum value inside the Pet class itself , which is essentially wrapping this in a getter.
public FoodType getFoodType(String foodTypeStr){
return FoodType.valueOf(foodTypeStr);
}
This will make sure only instance variables of child classes can invoke it. Hence you can do something like this,
dog01.feed(dog01.getFoodType("DRY"));
This can be made protected and ovveriden in child if needed.
I'm working on a problem where different animal types implement the same talk() method from Animal interface.
If you look at getAnimal() method, you can see that, when a new kind of animal is added to the program, inside of that method has to be changed as well.
I want to add new animals just by subclassing Animal without changing anything in the already existing classes.
For example, add an animal "Dog", criteria="loyal"; talk="woof".
Could you tell me, how it is possible? Below is my code:
interface Animal {
public void talk();
}
class Lion implements Animal {
#Override
public void talk() {
System.out.println("ROARRRRR");
}
}
class Mouse implements Animal {
#Override
public void talk() {
System.out.println("SQUEEEEEAK");
}
}
class Bison implements Animal {
#Override
public void talk() {
System.out.println("BELLOWWWWW");
}
}
class AnimalType {
public static Animal getAnimal(String criteria) {
// I refactor this method
if (criteria.equals("small")) {
return new Mouse();
} else if (criteria.equals("big")) {
return new Bison();
} else if (criteria.equals("lazy")) {
return new Lion();
}
return null;
}
}
public class AnimalExamples {
public static void main(String[] args) {
AnimalType.getAnimal("small").talk();
AnimalType.getAnimal("big").talk();
AnimalType.getAnimal("lazy").talk();
// how to add an animal "Dog" here, criteria="loyal"; talk="woof"
AnimalType.getAnimal("loyal").talk();
try {
AnimalType.getAnimal("small").talk();
} catch (Exception ex) {
System.out.println("Animal does not exists");
}
}
}
I searched on google, understood it can be done by reflection. But do not know how. If possible, could you help me with this, please? Thanks in advance!
Just so you know runtime class generation is extremely complex and not something recommended for beginners to the language. This would be an excellent scenario to use a map an anonymous classes.
class AnimalType {
private static final Map<String, Animal> animals = new HashMap<String, Animal>();
static {
// Populating map with default animals
addAnimal("big","BELLOWWWWW"); // bison
addAnimal("small","SQUEEEEEAK"); // mouse
addAnimal("lazy","ROARRRRR"); // lion
addAnimal("loyal","WOOF "); // dog
}
public static void addAnimal(String criteria, final String sound) {
// Assigning a anonymous implementation of animal to the given criteria
animals.put(criteria, new Animal() {
#Override
public void talk() {
System.out.println(sound);
}
});
}
public static Animal getAnimal(String criteria) {
// Returning an animal from the animals map
return animals.get(criteria);
}
}
If you really do insist on true runtime class generation or if you're curious how it works, check out ByteBuddy.
Old question, but here is how to create class... For me the easy way is to use Javassist.
I created a small example here: http://hrabosch.com/2018/04/08/generate-class-during-runtime-with-javassist/
But here is main point:
public static Class generateClass(String className, String methodName, String methodBody)
throws CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
StringBuffer method = new StringBuffer();
method.append("public void ")
.append(methodName)
.append("() {")
.append(methodBody)
.append(";}");
cc.addMethod(CtMethod.make(method.toString(), cc));
return cc.toClass();
}
So what I did... Via Javassist I made a class in ClassPool. Also I added a method inside this class and via reflection I invoked it.
Hope it helps.
Just keep on mind whatever you want to use in generated class, there
are NOT imports, so you have to use fully-qualified names.
Java doesn't support creating a class at runtime. However there are really better ways of achieving what you want here. I'll propose two.
Firstly, you could create an AnimalType class that contains all the shared behaviour about a species. You could then have an Animal class that takes an AnimalType as a constructor parameter.
Secondly, you could use a prototype design pattern. In this case the Animal class would need a clone method to create a new animal from the prototype. The factory class could then have a list of the prototypes and use whatever logic you desire to choose the correct prototype to clone.
Comment below if you want further details or sample code for either of these options.
you have to define the dog class
class Dog implements Animal {
#Override
public void talk() {
System.out.println("woof");
}
}
and add the if else to AnimalType
} else if ("loyal".equals(criteria)) {
return new Dog();
}
Let's say I have following interface:
interface Mammal {
void marry(Mammal m);
Mammal giveBirthTo();
}
However, this doesn't say quite exactly what I want.
Obviously, a human can't marry a dog, nor give birth to a cat. So how can I embed this information into the interface, such that the input type and output type can be changed automatically as it gets implemented?
You could use generics and change your design.
Something in the lines of:
interface Marriable<T extends Mammal> {
void marry(T sweetHalf);
T giveBirthTo();
}
... where Mammal is your top interface or abstract class, and Human, Dog, Unicorn etc. extend / implement it.
You can generify your interface using a recursive type variable:
interface Mammal<T extends Mammal<T>> {
void marry(T m);
T giveBirthTo();
}
This way, the Java compiler can give you a certain validation level. Notice however that this approach is still open to abuse. For example:
class Cat implements Mammal<Cat> {
#Override void marry(Cat cat) { ... }
#Override Cat giveBirthTo() { ... }
}
class Dog implements Mammal<Cat> { // implements wrong interface
#Override void marry(Cat cat) { ... }
#Override Cat giveBirthTo() { ... }
}
The compiler can only assure that you implement the Mammal interface by some sub type of the same interface, but not by the particular class that implements it. This latter type constraint cannot be expressed in the Java programming language.
Generics. Try with
private static interface Race {
}
private static class Human implements Race {}
private static class Canine implements Race {}
private static interface Being<R extends Race> {
void marry(Being<R> other);
Being<R> giveBirthTo();
}
private void tryMe() {
Being<Human> aHuman = new Being<Human>() {
#Override
public void marry(Being<Human> other) {
}
#Override
public Being<Human> giveBirthTo() {
return null;
}
};
Being<Canine> aCanine = new Being<Canine>() {
#Override
public void marry(Being<Canine> other) {
}
#Override
public Being<Canine> giveBirthTo() {
return null;
}
};
aHuman.marry(aCanine); // not possible
}
I am having a problem with Factory pattern when it use with Inheritance,
This is my code
public class Animal {
public int numberOfLegs() { return 2 ;}
}
public class Cat extends Animal {
public String getSound() {return "Maaaw";}
}
public class Dog extends Animal {
public String getSound() {return "woof";}
}
public class AnimalFactory {
public Animal getAnimal(String name){
Animal an= null ;
if(name=="cat"){an = new Cat();}
else if(name=="dog"){an=new Dog();}
return an ;
}
}
public class FactoryDemo {
public static void main(String[] args) {
AnimalFactory anmF=new AnimalFactory();
Animal anm=anmF.getAnimal("cat") ;
System.out.println("legs : "+anm.numberOfLegs()); // working fine
System.out.println("sound : "+anm.getSound()); // giving error
}
}
When I run this, I can't go to the getSound() method. It giving a error.
This'll work fine if I define the Animal class as Abstract class,
But I want to how to deal Factory pattern such a situation like this.
You need to add an abstract method for getSound
public abstract class Animal {
public int numberOfLegs() { return 2 ;}
public abstract String getSound();
}
Change your code to:
public abstract class Animal {
public int numberOfLegs() {
return 2;
}
public abstract String getSound();
}
public class Cat extends Animal {
public String getSound() {
return "Maaaw";
}
}
public class Dog extends Animal {
public String getSound() {
return "woof";
}
}
public class AnimalFactory {
public Animal getAnimal(String name) {
Animal an = null;
if ("cat".equals(name)) {
an = new Cat();
} else if ("dog".equals(name)) {
an = new Dog();
}
return an;
}
}
You shall add abstract method, and use equals in your factory method instead of using == on Objects.
The code you included, is nothing like a Factory anything. If you refer to the Factory Method Pattern then, what you implemented as part of your OP is an incorrect implementation. There are two "Factory" code designs, one is the Factory Method Pattern I indicated before (your code is definitely not that) and the Factory recommended in the Effective Java book, which is the design of choice for the Java JDK i.e. the valueOf or create* methods.