Attempts to design an object model - using enums
I am trying to create an object model (for C #) and cannot find a better way to store data. I'll try to use a simple example to illustrate this!
I have a "pet" object that can be one of "cat", "dog", etc. So, I created a class "pet" with an enumeration "petType" to store this.
Now it gets tricky. If the "pet" is a "cat" then its "food" can be "fish", "milk", etc. If it is a "dog", then its "food" can be "meat", "cookies", or something like that.
Now I have to create a large enum for "fish", "milk", "meat" and "biscuits" and somehow code it so that "cat" cannot be assigned to "food.meat"? It wouldn't make sense for my "pets" class to have an enumeration of "catfood" and "dogfood" because that is not extensible and will end up containing many numbered enums.
Is there an elegant solution that I am not seeing?
source to share
Try # 2. Seems to be correct
interface IPet { }
class Cat : IPet
{
public void eat(CommonFood food) { }
public void eat(CatFood food) { }
}
class Dog : IPet
{
public void eat(CommonFood food) { }
public void eat(DogFood food) { }
}
interface IFood { }
abstract class CommonFood : IFood { }
abstract class CatFood : IFood { }
abstract class DogFood : IFood { }
class Milk : CommonFood { }
class Fish : CatFood { }
class Meat : DogFood { }
class Program
{
static void Main(string[] args)
{
Dog myDog = new Dog();
myDog.eat(new Milk()); // ok, milk is common
myDog.eat(new Fish()); // error
}
}
source to share
First, the cat and dog should probably be subclassified from pet , suggesting that there are some common characteristics of all pets.
Further, I don't understand what you are planning to do with the food . Is there a pet as an object model , or will there be methods as it is that there is food as an argument ?
source to share
I don't know about your cat, but my cats eat meat and very little!
and scraps of dining tables like cookies are bad for dogs (and cats)
but as an aside, why are you wrapping up with enums? and why does your "pet" object have a "petType" property? A simple / direct representation would be the Pet class with subclasses of Cat and Dog, but a more practical representation would be the Pet interface, which can be applied to any Animal object.
source to share
I agree with Tautologistics about subclassing Cat and Dog Pet (or implementing the Pet interface!), Instead of having an explicit PetType enumeration and field. Explicit "type flags" are incompatible with true OO design.
When it comes to relationships with food, you can think about implementing two concepts:
- The "business rule" for Pet, implemented using the method
acceptsFood(FoodEnum food)
. This method will be responsible for verifying the legality of the food prescription. - The "favorite food" property of any instance
Pet
(subclass) that allows an individual pet to identify a favorite food (from a set of foods that are actually accepted by its species).
source to share
It sounds like you need to consider cat and dog food as a kind of strategy and compose the right food with the appropriate pet using a simple factory.
Here's one option in Ruby.
class CatFood
attr_reader :items
def initialize
@items = ['fish', 'milk']
end
end
class DogFood
attr_reader :items
def initialize
@items = ['meat', 'biscuits']
end
end
class NoFood
attr_reader :items
def initialize
@items = []
end
end
class Pet
attr_reader :food
def initialize(food)
@food = food
end
end
class PetFactory
def create_dog
Pet.new(DogFood.new)
end
def create_cat
Pet.new(CatFood.new)
end
def create_unknown_pet
Pet.new(NoFood.new)
end
end
source to share