Reputation: 8055
I am trying to design an object model (for C#), and can't work out the best way to store the data. I'll try to use a simple example to illustrate this!
I have an object "pet", which could be one of, "cat", "dog" etc. So I have created an "pet" class with a "petType" enum to store this.
Now this is where it gets tricky. If an "pet" is a "cat", then its "food" could be one of "fish", "milk" etc. If it is a "dog" then its "food" could be "meat", "biscuits" or something.
Now should I create a big enum for "fish", "milk", "meat" and "biscuits" and somehow code it so that a "cat" cannot be assigned "food.meat"? It wouldnt really make sense for my "pet" class to have a "catfood" and "dogfood" enum, because thats not extensible and it will end up storing loads of enums that are null.
Is there an elegant solution to this that I'm not seeing?
Upvotes: 1
Views: 607
Reputation: 10207
It sounds like you need to consider cat/dog food as sort of strategies, and compose appropriate food with appropriate pet using a simple factory.
Here is one variation 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
Upvotes: 0
Reputation: 61243
i don't know about your cat, but my cats eat meat and very little else!
and eating table scraps like biscuits is bad for dogs (and cats)
but that aside, why are you screwing around with enums? and why does your 'pet' object have a 'petType' property? A simple/direct representation would be a Pet class with Cat and Dog subclasses, but a more practical representation would be a Pet interface that could be applied to any Animal object.
Upvotes: 0
Reputation: 30943
I agree with Tautologistics on having Cat and Dog subclass Pet (or implement a Pet interface!), rather than having an explicit PetType enumeration and field. Explicit "type flags" are out of step with true OO design.
As for the food relationship, you might consider implementing two concepts:
acceptsFood(FoodEnum food)
method. This method would be responsible for checking the legality of a food assignment.Pet
(subclass) instance that allows the individual pet to have a favorite food identified (out of the set of foods that are actually accepted by its species).Upvotes: 0
Reputation: 100298
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
}
}
Upvotes: 2
Reputation: 1508
First, cat and dog should probably be subclassed from pet, assuming there are some common properties of all pets.
Next, I'm not clear what you are planning to do with food. As an object model does a pet hold a type of food or will there be methods such as eat that will take food as an argument?
Upvotes: 0