Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have been reading up on programing to interfaces rather than implementation. One area I am not properly understanding is how to deal with non-interface methods. For example an interface IAnimal and a Cat class that implements it. My examples are in C# but I think it should also apply to other languages.
public interface IAnimal
{
void Eat();
}
public class Cat : IAnimal
{
public Cat()
public void Eat()
{
//Do something
}
public string Meow()
{
return "meow";
}
}
From what I've read it seems like I should be trying to work with the interface rather than the cat implementation such as,
Main()
{
IAnimal cat = new Cat();
}
But this leaves me without access to my meow method as it is not a part of the IAnimal interface. Should I be creating another interface ICat which implements IAnimals and have Cat implement it? And does this mean that all methods should be an implementation from an interface or abstract class? Or am I doing something else here wrong.
Thanks for your help.
What you would do is you is have another interface that represent's speaking animals and either inherit from IAnimal or add it as a 2nd interface. Classes that have animals that speak implement the 2nd interface.
with a inherited interface.
public interface IAnimal
{
void Eat();
}
public interface ISpeakingAnimal : IAnimal
{
string Speak();
}
public class Cat : ISpeakingAnimal
{
public Cat()
public void Eat()
{
//Do something
}
public string Speak()
{
return "meow";
}
}
public class Fish : IAnimal
{
public Fish()
public void Eat()
{
//Do something
}
}
With a 2nd decorator interface
public interface IAnimal
{
void Eat();
}
public interface ISpeakable
{
string Speak();
}
public class Cat : IAnimal, ISpeakable
{
public Cat()
public void Eat()
{
//Do something
}
public string Speak()
{
return "meow";
}
}
public class Fish : IAnimal
{
public Fish()
public void Eat()
{
//Do something
}
}
If you need the method not be Speak() but instead be Meow() you can use explicit interface implementations to expose the Speak() method only though that interface.
public class Cat : ISpeakingAnimal
{
public Cat()
public void Eat()
{
//Do something
}
string ISpeakingAnimal.Speak()
{
return Meow();
}
public string Meow()
{
return "meow";
}
}
The point of an interface is to define behavior common to classes that implement that interface. You are correct in noting that defining cat like so:
IAnimal cat = new Cat();
leaves you unable to access methods in the Cat class that are not in IAnimal. So why is it encouraged to implement things in this way?
The answer is simple: it makes it very easy to change the code later on. For example, if we have a Dog class that implements IAnimal, like so:
public class Dog : IAnimal
{
// some methods
}
then we can very easily replace our Cat class with the Dog class, without having to change any other code. In other words, we can replace:
IAnimal cat = new Cat();
with
IAnimal dog = new Dog();
without having to change any other code in the entire program (besides the variable names). This is because defining Cat and Dog with respect to IAnimal forces them to only use methods found within IAnimal, though they may be implemented differently in Cat and Dog.
Of course, if you want to use something specific only to Cat or Dog, you will have to define the class explicitly, as mentioned by #Erick in his answer, like so:
Cat cat = new Cat();
In general, you should try to define as many common behaviors in the interface as possible, only explicitly casting to a certain class like Cat or Dog when absolutely necessary. This makes your code a lot more versatile and changeable.
If you need to access the method it would be necessary to make an explicit cast.
In this case it would be more interesting to leave your Meow() method more generic for other possible classes that could implement it:
public interface IAnimal
{
void Eat();
void Speak();
}
public class Cat : IAnimal
{
public void Eat() { }
public string Speak()
{
return "meow";
}
}
public class Dog : IAnimal
{
public void Eat() { }
public string Speak()
{
return "au";
}
}
My two cents on this topic is that it's true that you need to depend on abstractions (i.e. interfaces) rather than implementations.
BTW, doesn't this going too far? There's no need to define an interface for any class within your object model. Usually you define interfaces if you need to accept certain objects fulfilling a given contract.
For example, I wouldn't define IAnimal or ICat interfaces. Probably I would define an abstract class Animal and just a concrete class Cat.
If for some reason I need to accept living beings in some API that could eat I would define an interface like this:
public interface IFeedable
{
void Feed(Food food);
}
and if a living being can talk:
public interface ITalkative
{
void Talk(Food food);
}
Unless there's no feature/property/behavior that could be exclusive to animals, I would leave these interfaces as is.
public abstract class Animal : ITalkative, IFeedable
{
public Animal(AudioPlayer audioPlayer)
{
AudioPlayer = audioPlayer;
}
private AudioPlayer AudioPlayer { get; }
public abstract void Feed(Food food);
public void Talk()
{
// Probably you would want to load an animal sound library
// here, and later pass the audio player with the sound library
// already loaded
OnTalk(AudioPlayer.LoadLibrary("animals"));
}
protected abstract void OnTalk(AudioLibrary audioLibrary);
}
public sealed class Cat : Animal
{
public Cat(AudioPlayer audioPlayer) : base(audioPlayer)
{
}
public override void Feed(Food food)
{
if(food is Vegetable)
{
throw new NotSupportedException("MeeEEEEooW (=O ò.ó)=O!!");
}
else if(food is Meat)
{
// Proceed to eat this meat!
}
}
protected override void OnTalk(AudioLibrary audioLibrary)
{
audioLibrary.Play("sweet-cat");
}
}
And if somewhere you need to make an object to talk:
ITalkative talkative = some as ITalkative;
if(talkative != null)
{
talkative.Talk();
}
Or if you need to feed the object:
IFeedable feedable = some as IFeedable;
if(feedable != null)
{
feedable.Feed(new Vegetable());
}
As you can see, you don't define interfaces for everything, but just for those things that you need to handle inside some API and you don't care who can do some actions and/or own some data, but you just care about the object can do or exposes certain behaviors and data respectively.
Related
I have seen an Interface instance being generated from a class many times. Why do we use interface this way? An interface instance is created only itself with the help of the derived class and we can access only these interface members through this instance. How does this give an advantage? I'm so confused.
interface IPrint
{
void Print();
}
class Sample : IPrint
{
public void Print()
{
Console.WriteLine("Print...");
}
public void Sample()
{
Console.WriteLine("Sample...");
}
}
class Program
{
static void Main(string[] args)
{
IPrint print = new Sample();
print.Print();
}
}
Interfaces define that a class MUST be able to do something. This means that you know the object being worked on will do what you want to be able to do. It allows you greater freedom and is one of the advantages of OOP. This is a deep topic but a very basic example would be this:
public interface IAnimal
{
string Speak();
}
public class Dog : IAnimal
{
public string Speak()
{
return "Woof, woof";
}
}
public class Cat : IAnimal
{
public string Speak()
{
return "Meow";
}
}
public class Parrot : IAnimal
{
public string Speak()
{
return "Sqwark!";
}
}
Then you could use any animal you like!
class Program
{
static void Main(string[] args)
{
// Writes Woof, Woof
IAnimal animal = new Dog();
Console.WriteLine(animal.Speak());
// Now writes Meow
animal = new Cat();
Console.WriteLine(animal.Speak());
// Now writes Sqwark etc
animal = new Parrot();
Console.WriteLine(animal.Speak());
}
}
This also allows you to then get into things like Inversion Of Control where you would take an item in like this and you could pass a dog, cat or parrot and the method would always work, not knowing or caring which animal it was:
public void ShoutLoud(IAnimal animal)
{
MessageBox.Show("Shout " + animal.Speak());
}
This then makes ShoutLoud unit testable because you could use a mock object rather than a real animal. It basically makes your code flexible and dynamic rather than rigid and tightly coupled.
Also, expanding on Matthew's question. In C# you can only inherit from one base class but you can have multiple interfaces. So, you could have:
public class Dog : IAnimal, IMammal, ICarnivor
This allows you to have small interfaces (recommended) that then allow you to build up so giving maximum control over what an item can / must do.
Using an interface this way gives you the ability to create methods that use standard template of the interface. So here you might have many classes of printer that all inherit from IPrinter
class SamsungPrinter : IPrinter
{
// Stuff and interface members.
}
class SonyPrinter : IPrinter
{
// Stuff and interface members.
}
interface IPrinter
{
void Print();
}
So for each type SamsungPrinter, SonyPrinter, etc. you can pre-process using something like
public static void PreProcessAndPrint(IPrinter printer)
{
// Do pre-processing or something.
printer.Print();
}
You know from inheriting from IPrinter and using that type in the method parameters that you can always safely use the Print method on what ever object is passed.
Of course there are many other uses for using interfaces. One example of their use is in design patterns, in particular the Factory and Strategy patterns. The description of which and examples can be found here.
I hope this helps.
But how does this differ from, for example, using a base class with virtual methods?
You are all in the assumption that one programmer or one program writes the interface and the classes, but this doesn't always have to be this way.
Maybe you have a complete finished program that works with animals and you have this worked out using:
public abstract class Animal { public abstract string Speak(); }
And then some day you download some awesome DLL from nuget that shows pictures for animals. The class library contains a contract - interface - 'IAnimal':
namespace AwesomeAnimalLibrary
{
public interface IAnimal
{
string AnimalName;
}
}
The class library also maybe contains :
namespace AwesomeAnimalLibrary
{
public class AnimalPhotos
{
[Byte] GetPhotos(IAnimal animal);
}
}
What could you do now ? Your bas class Animal can implement the AwesomeAnimalLibrary IAnimal interface and that's it.
Don't assume that other people will use you abstract base classes but work together using interface contracts.
Interface can not have instance because interface implements only signatures of properties or methods. Interface is just a pointer to an instance of some class:
interface IExample
{
// method signature
void MyMethod();
}
public class MyClass : IExample
{
// method implementation
public void MyMethod()
{
ConsoleWriteline("This is my method");
}
}
// interface pointing to instance of class
IExample ie = new MyClass();
ie.MyMethod();
I am creating an Animal class which implements IAnimal interface. Then, both Cats and Dogs classes implement IAnimal interface. Currently I keep only 3 simple methods inside IAnimal for short demonstration. The main class Animals is constructed by using Dependency Injection (DI).
When IAnimal has more methods, for example: Cats class only implements SomethingOnlyCatsDo method, Dogs class implements SomethingOnlyDogsDo method, then there will be more unnecessary implementations inside each of those classes (like Cats().CatchDisk() or Dogs().CatchMouse() in current example).
My question is, is there any way which can help me keep using DI but avoid this growing of unnecessary implementations?
public interface IAnimal
{
void Sound();
void CatchMouse();
void CatchDisk();
// What if there are more methods here
//string GetOwnerName();
//void SomethingOnlyCatsDo();
//void SomethingOnlyDogsDo();
}
public class Cats : IAnimal
{
public void Sound()
{
Console.WriteLine("Meow meow");
}
public void CatchMouse()
{
Console.WriteLine("Catching mouse");
}
public void CatchDisk()
{
throw new NotImplementedException();
}
}
public class Dogs : IAnimal
{
public void Sound()
{
Console.WriteLine("Woof woof");
}
public void CatchDisk()
{
Console.WriteLine("Catching disk");
}
public void CatchMouse()
{
throw new NotImplementedException();
}
}
// Main class
public class Animals
{
private readonly IAnimal _animal;
public Animals(IAnimal animal)
{
_animal = animal;
}
public void Sound()
{
_animal.Sound();
}
public void CatchADisk()
{
_animal.CatchDisk();
}
public void CatchAMouse()
{
_animal.CatchMouse();
}
}
If following SOLID principles, and especially the I (Interface Segregation, https://en.wikipedia.org/wiki/Interface_segregation_principle), IAnimal should not have CatchDisk or CatchMouse methods. Instead you should have IAnimal with the Sound() method, and separate interfaces ICatchesMouse and ICatchesDisk. This way no Animal has to implement unnecessary methods.
You can use Interface Segregation Principle.
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.
Your IAnimal interface will only have Sound(), then you make a new interface called ICat that inherits from IAnimal and this interface will have CatchMouse(). Your class Cats will inherit from ICat.
Here's a practical example.
Right now I have a kind of dilemma. There is a class structure that is similar to the following one:
public interface IMammal
{
void Eat();
}
public interface IBarking
{
void Bark();
}
There are instances of IBarking and IMammal. Theoretically our animal can be either of them or just one. Cow is as you can see IMammal, and Dog is IMammal and IBarking. In theory we could even have someone who can bark, but isn't a mammal.
public class Mammal : IMammal
{
public void Eat()
{
Console.Write("Om-nom-nom");
}
}
public class Cow : Mammal
{
}
public class Dog : Mammal, IBarking
{
public void Bark()
{
Console.Write("Bark-bark!!!");
}
}
Here is a Farm, where only one animal lives:
public class Farm
{
private readonly IMammal _animal;
public Farm(IMammal animal)
{
_animal = animal;
}
public void Feed()
{
_animal.Eat();
}
public void Guard()
{
var dog = _animal as IBarking;
if (dog != null)
dog.Bark();
}
}
The problem, I can see here, is that we assume that IBarking is always IMammal. What is wrong with this design, how could it be fixed?
Such simplified examples hardly make any sense. You're missing the "problem case" and what you want to do then. Show a class that implements IBarking but not IMammal and what problems arise when you pass it to Farm. Anyway, given the premises:
Interface IMammal exists.
Interface IBarking exists.
A class implementing IBarking does not have to implement IMammal.
Class constructor Farm has to accept IBarking and IMammal.
Current class constructor accepts IMammal.
In this case you either need a new constructor, a new private member and more code to choose between the two, or an overlapping interface. I'd go with the latter: IFarmable.
Then you need:
public interface IMammal : IFarmable
public interface IBarking : IFarmable
public Farm(IFarmable farmable) { ... }
Most likely you have other constraints, like "but I want to call Eat() on the variable passed into the constructor", but then your description ("we assume that IBarking is always IMammal") is incorrect or incomplete and you need to move Eat() to the IFarmable interface.
I'll try to interpret your intention.
You want to have a farm where animals grow up (to later be slaughtered for food).
You might need another animal guarding them (might since you tried the cast).
A better design for that would be:
public class Farm
{
private readonly IMammal[] _animals;
public Farm(IMammal[] animals)
{
_animals = animals;
}
public void Feed()
{
foreach (var animal in _animals)
animal.Eat();
}
public IBarking GuardingAnimal { get; set; }
public void Guard()
{
if (GuardingAnimal != null)
GuardingAnimal .Bark();
}
}
Changes from your design:
I've made it crystal clear that there can be a guarding animal
The guarding animal is optional (as it's assign through a property instead of the constructor).
The reason that I wanted to make that distinction is that most animals are passive (you feed and harvest them) while the guard animal has a specific use case and should therefor not be hidden among the others.
If you want to feed the dog you, you should make that interface inherit IMammal (unless you introduce more functionality in mammal in which case you should extract IFeedable or similar).
Obviously trying to simplify the problem here. I have a base class and a number of derived classes:
public class Mammal { }
public class Cat : Mammal { }
public class Dog : Mammal { }
And a utility class:
public static class AnotherClass
{
public static void GiveFood(Cat cat) {}
public static void GiveFood(Dog dog) {}
}
Somewhere else is a method, Feed, which takes a Mammal, and from within there i want to call the right overload on AnotherClass:
public void Feed(Mammal mammal) {
// if mammal is a cat, call the AnotherClass.GiveFood overload for cat,
// if it's a dog, call the AnotherClass.GiveFood for dog, etc.
}
One way to do that would be to do something like:
public void Feed(Mammal mammal) {
if (mammal is dog)
AnotherClass.GiveFood((Dog)mammal);
if (mammal is Cat)
AnotherClass.GiveFood((Cat)mammal);
}
...but I actually have a huge number of animals derived from Mammal. Is there a nicer way to do what I want to do in Feed()? Is there any way I can avoid having Feed() end up being a huge ugly method filled with these "if x is y then call z"-statements?
I don't usually like using dynamic, but this is one of the cases where I think it's appropriate:
public void Feed(Mammal mammal) {
Anotherclass.GiveFood((dynamic)mammal);
}
That will resolve the correct overload at runtime, without knowing the type in advance.
Strictly speaking, this probably isn't going to be the fastest method, but as you point out, the alternatives can be a real pain to maintain, and/or hard to read. In this case, dynamic dispatch is elegant and will automatically incorporate any overloads you add in the future.
As Chris Sinclair points out, you could also add a catchall method to detect any invalid calls and provide a friendlier exception than the runtime error you'd receive if no matching GiveFood() overload could be found:
public static class AnotherClass
{
public static void GiveFood(Cat cat) {}
public static void GiveFood(Dog dog) {}
public static void GiveFood(Mammal mammal)
{
throw new AnimalNotRecognizedException("I don't know how to feed a " + mammal.GetType().Name + ".");
}
}
I think it's the animal's responsibility to process food, not the feeder. Otherwise you'll run into the problem you now have:
public void Feed(Mammal mammal) {
if (mammal is Duck)
{
((Duck)mammal).PryOpenBeak();
((Duck)mammal).InsertFeedingTube();
((Duck)mammal).PourDownFood();
}
}
And so on, although ducks aren't mammals.
Anyway, your Mammal class should have an abstract method Feed(Food food), and the animal itself will have to figure out how to process the food. This way when later adding a new mammal, you won't have to update the feeder with the feeding logic for this new mammal.
#Chris's comment: then the animal could implement the proper IFoodXEater interface that contains a Feed(IFoodX) method, and then the feeder can look that up, although then you're back at square one:
if (mammal is IFishEater)
{
((IFishEater)mammal).Feed(new Fish());
}
My Recommendation:
Step 1: Create an interface IMammal
<!-- language: c# -->
public interface IMammal
{
void Feed();
}
Step 2: (Optional) Implement a Base class BaseMammal
public class BaseMammal : IMammal
{
public void Feed()
{
Trace.Write("basic mammal feeding");
//a basic implementation of feeding, common to all or most mammals
}
}
Step 3: Implement your inherited classes
public class Cat : BaseMammal
{
public void Feed()
{
Trace.Write("cat feeding");
BePicky();//some custom cat like functionality
base.Feed(); //and afterwards its still just a mammal after all
}
}
public class Gruffalo : BaseMammal
{
public void Feed()
{
Trace.Write("Gruffalo feeding");
WeirdWayOfEating();//the base implementation is not appropriate
}
}
Step 4: Use! (random example included)
List<IMammal> pets = new List<IMammal>()
{
new Cat(catValues),
new Gruffalo(gruffaloValues)
};
foreach(var pet in pets)
{
pet.Feed();
}
Each animal will be fed by their own implementation. Lo and behold - your complex code is now simple. I would also recommend that you read "Head First Design Patterns", which explains this and many other concepts. http://www.amazon.co.uk/Head-First-Design-Patterns-Freeman/dp/0596007124
If you don't mind the effort of creating a type map, you can fake double dispatch like so:
[EDIT] This new, improved version handles subclasses better. If you have a class derived from another mammal class (such as Pug derived from Dog in the example below) then you don't need to explicitly add a feeder for class Pug - it will automatically call the feeder for its base class, Dog.
But you can have a specific feeder for a derived class if you want, as demonstrated by the Manx class below.
Using dynamic is much much easier though! I just wanted to show how it could look if you weren't using dynamic.
using System;
using System.Collections.Generic;
namespace Demo
{
public class Mammal {}
public class Cat: Mammal {}
public class Pig: Mammal {}
public class Dog: Mammal {}
public class Pug: Dog {}
public class Manx: Cat {}
public static class Feeder
{
static readonly Dictionary<Type, Action<Mammal>> map = createMap();
static Dictionary<Type, Action<Mammal>> createMap()
{
return new Dictionary<Type, Action<Mammal>>
{
{typeof(Cat), mammal => GiveFood((Cat) mammal)},
{typeof(Dog), mammal => GiveFood((Dog) mammal)},
{typeof(Manx), mammal => GiveFood((Manx) mammal)}
};
}
public static void GiveFood(Mammal mammal)
{
for (
var currentType = mammal.GetType();
typeof(Mammal).IsAssignableFrom(currentType);
currentType = currentType.BaseType)
{
if (map.ContainsKey(currentType))
{
map[currentType](mammal);
return;
}
}
DefaultGiveFood(mammal);
}
public static void DefaultGiveFood(Mammal mammal)
{
Console.WriteLine("Feeding an unknown mammal.");
}
public static void GiveFood(Cat cat)
{
Console.WriteLine("Feeding the cat.");
}
public static void GiveFood(Manx cat)
{
Console.WriteLine("Feeding the Manx cat.");
}
public static void GiveFood(Dog dog)
{
Console.WriteLine("Feeding the dog.");
}
}
class Program
{
void test()
{
feed(new Cat());
feed(new Manx());
feed(new Dog());
feed(new Pug());
feed(new Pig());
feed(new Mammal());
}
void feed(Mammal mammal)
{
Feeder.GiveFood(mammal);
}
static void Main()
{
new Program().test();
}
}
}
If more than one animal shares the feeding behavior, I'll suggest to use the strategy pattern to encapsulate the feeding behavior in an interface and concrete implement each behavior for each group of animals
you will be using composition instead of inheritance
check the head first design patterns for this one I think it will be a good implementation in your case
I need to hold a list of object types that are allowed to do certain actions.
Example Animal has 3 descendants Tiger, Human, Hippo
I want to allow only Tigers and Hippos to be held in zoo cages? I need a list of animal types.
I would love something better than List<Type>
This is just a simplified example. I don't like animals in cages..
edit
Since it's not clear. I want to hold object types in the list and not actual objects.
Example:
List<Type> types = new List<Type>();
types.Add(typeof(Hippo));
types.Add(typeof(Tiger));
This has the limit that a programmer can do types.Add(typeof(Human)) and this is what I wan't to dissallow.
edit2
Just to clarify my question. I want to be able to dynamically Register allowed types and not having consequent ifs as some answers bellow.
If you want a list of only certain types:
There isn't anything in generics that can support what you are asking for, so simply create a custom type that allows you to store Type types and have code at runtime for guarding against invalid entries:
public class CagedTypes
{
private readonly List<Type> _types;
public void Add(Type t)
{
if (t == typeof(Hippo) || t == typeof(Tiger))
_types.Add(t);
}
}
Although I can't see why you might need this.
Alternative if you want a list of only certain types:
Do the same as above, but include the interface below and change the add check to something like:
public void Add(Type t)
{
if (t.GetInterfaces().Contains(typeof(ICanBeHeldInZooCage)))
_types.Add(t);
}
You could also use attributes, as you can query a type for any attributes using the GetAttributes method.
If you wish to only have certain instances in a list:
Create a marker interface:
public interface ICanBeHeldInZooCage
That Tiger and Hippo implement (doesn't have to do anything), then you can have:
var cagedAnimals = new List<ICanBeHeldInZooCage>();
Approach1 - via interfaces:
public interface ICageable
{ }
public abstract class Animal
{}
public class Hippo : Animal, ICageable
{}
public class Human : Animal, ICageable
{}
public IEnumerable<Type> GetCageableAnimals()
{
return GetAssemblyTypes(assembly:typeof(Animal).Assembly)
.Where(type=>IsDerivedFrom(type, typeof(Animal)))
.Where(type=>ImplementsInterface(type,typeof(ICageable)));
}
Approach 2 - via attribute:
public class InCageAttribute : Attribute
{ }
public abstract class Animal
{}
[InCage]
public class Hippo : Animal
{}
public class Human : Animal
{}
public IEnumerable<Type> GetCageableAnimals()
{
return GetAssemblyTypes(assembly:typeof(Animal).Assembly)
.Where(type=>IsDerivedFrom(type, typeof(Animal)))
.Where(type=>MarkedByAttribute(type,typeof(InCageAttribute)));
}
UPDATE
IMPORTANT
Both these approaches provide only runtime check. having compilation check implementation would be better, but don't know for know how to achieve that.
UPDATE2
For dynamic registration:
public class CageRegistry
{
private List<Type> _allowedTypes = new List<Type>();
public IEnumerable<Type> AllowedTypes{get{return _allowedTypes;}}
public bool TryAdd(Type type)
{
if(ImplementsInterface(type, typeof(ICageable)))// for approach with attributes code is pretty similar
{
_allowedTypes.Add(type);
return true;
}
return false;
}
}
PS2
Sorry for not implemented methods like MarkedByAttribute, IsDerivedFrom and ImplementsInterface - I just don't have visual studio on current machine yet and don't remember api exactly.
How about an Interface?
public interface ICageable {}
public abstract class Animal {}
public class Hippo : Animal, ICageable {}
public class Tiger : Animal, ICageable {}
public class Human : Animal, ICageable {}
public class Ape : Animal {}
....
List<ICageable> ZooAnimals = new List<ICageable>{hippo, tiger, human};
(writing from a Planet of the Apes perspective)
and if you need the types themselves in a list, well types are instances of the Type type, so whatever you create it will be a collection of types. You could encapsulate is like this:
public class CageableTypesCollection :
{
private List<Type> _cageableTypes;
public CageableTypesCollection()
{
_cageableTypes = new List<Type>();
}
public RegisterType(Type t)
{
if (!typeof(ICageable).IsAssignableFrom(t))
throw new ArgumentException("wrong type of type");
_cageableTypes.Add(t);
}
public UnregisterType(Type t)
{
....
}
.....
}
I would use an interface to determine if an animal is a ZooAnimal
public class Animal
{
public string Name;
}
public class Tiger : Animal, IZooAnimal
{
}
public class Human : Animal
{
}
public interface IZooAnimal
{
//Some zoo animal properties
}
And then check if the animal is a Zoo Animal if (a is IZooAnimal) below is a zoo class which you could use.
public class Zoo
{
public List<IZooAnimal> AnimalsInZoo = new List<IZooAnimal>();
public void AddAnimal(IZooAnimal a)
{
AnimalsInZoo.Add(a);
}
}
EDIT:
Ok now to do this with types and constrain the types to a ZooAnimal I have made a generic zoo class which takes T where T is a ZooAnimal - you could have a list of ZooAnimals or a list of tigers in our case.
public class Zoo<T> where T : IZooAnimal
{
public List<Type> AnimalTypes = new List<Type>();
public void AddType(Type a)
{
if (typeof(T) == a)
AnimalTypes.Add(a);
}
}
This will add type Tiger to the AnimalsInZoo. Hope this works for you.
Zoo<IZooAnimal> cage = new Zoo<IZooAnimal>();
cage.AddType(typeof(Tiger));
cage.AddType(typeof(Human));
Human is animal, Tiger is animal that should be in zoo. So in your case I'd create one more base class for Tiger and Hippo.
public class AnimalInZoo : Animal {}
public class Tiger : AnimalInZoo {}
public class Hippo : AnimalInZoo {}
public class Human : Animal {}
You can create helper function AddInZoo(AnimalInZoo obj) to add in you List<Type> m_Zoo:
void AddInZoo(AnimalInZoo obj)
{
m_Zoo.Add(obj.GetType());
}
The other option:
public abstract class Animal
{
public abstract bool IsCagable { get; }
}
And let the nested classes to implement their behavior.
Later then, the some sort of Zoo class which is mostly presented in the answers in this topic, inside the method Add must do the check:
public sealed class ZooList : List<Animal> // I believe you need Animal, not Type
{
// ... some implementations ...
public override sealed void Add(Animal animal)
{
if (!animal.IsCagable)
// Prevent from adding.
}
}