I want to be a little be more descriptive in my class names. I have three identical classes that look like this:
public class Dog
{
public string name;
public int id;
public Dog(){}
public Dog(DataRow dr)
{
name = dr["Name"];
id = dr["Id"];
}
}
public class Cat
{
public string name;
public int id;
public Cat(){}
public Cat(DataRow dr)
{
name = dr["Name"];
id = dr["Id"];
}
}
public class Horse
{
public string name;
public int horseId;
public Horse(){}
public Horse(DataRow dr)
{
name = dr["Name"];
horseId= dr["horseId"];
}
}
How do I avoid code duplication by using a base class? What are the best practicies? pplease note that horse has a property called HorseId instead of Id. Thanks.
Use inheritance.
public class Animal
{
public string name;
public int id;
public Animal() {}
public Animal(DataRow dr)
{
name = (string)dr["Name"];
id = (int)dr["Id"];
}
}
// unfortunately, constructors aren't inherited automatically in C#.
public class Cat : Animal
{
public Cat() : base() {}
public Cat(DataRow dr) : base(dr) {}
}
public class Dog : Animal
{
public Dog() : base() {}
public Dog(DataRow dr) : base(dr) {}
}
public class Horse: Animal
{
public int horseId { get { return id; } set { id = value; } }
public Horse() : base() {}
public Horse(DataRow dr) : base(dr) {}
}
EDIT: as Blorgbeard says, you can make Animal an abstract class if you want - that will prevent instantiation (new Animal() will be illegal; client code will have to pick a specific subclass).
I would make an interface called IAnimal that has properties name and id and have all 3 classes above implement this interface. Note is is slightly different than what you have here, as what you have here shows public variables, not public properties. If you want to maintain variables, then I would use a base class Animal with public variables name and id and convert horseId to a property that, interally, gets and sets the base id property like this public int horseId { get { return base.id; } set { base.id = value; } }
I'd do something like this - an abstract base class.
public abstract class Animal {
public string name;
public int id;
protected Animal() {}
protected Animal(DataRow dr) {
name = (string)dr["Name"];
id = (int)dr["Id"];
}
}
public class Cat : Animal {
public Cat() : base() {}
public Cat(DataRow dr) : base(dr) {}
}
Then just add a property to Horse (still leaving id as well)
public class Horse : Animal {
public int horseid { get { return id; } set { id = value; } }
public Horse() : base() {}
public Horse(DataRow dr) : base(dr) {}
}
This method doesn't allow you remove/hide id in the Horse class, so you will have both id and horseid, but they will use the same variable underneath.
As far as some good examples on object oriented design, I'd recommend two books.
The Object Oriented Thought Process
Agile Principles, Patterns and Practices in C# by Robert C. Martin. This book is just awesome at explaining great principles of OOP.
Related
I want to instantiate new object of type Dog. Dog class implements interface IAnimal. Animal can make baby animal and that baby animal can grow to be big animal of type dog.
public interface IAnimal
{
BabyAnimal baby();
int NumberOfLegs { get; set; }
}
public class Dog:IAnimal
{
public Dog()
{
}
public int NumberOfLegs { get; set; }
public BabyAnimal baby()
{
}
}
public class BabyAnimal
{
public IAnimal WillGrowToBe(BabyAnimal baby)
{
//here I want to instantiate new Dog object
}
}
You can model this more strongly, if you introduce the concept of baby and grown animals, in a generic fashion:
public interface IAnimal
{
int NumberOfLegs { get;}
}
public interface IBabyAnimal<TGrownAnimal>
: IAnimal
where TGrownAnimal : IGrownAnimal
{
TGrownAnimal WillGrowToBe();
}
public interface IGrownAnimal : IAnimal
{
}
public class Catepillar : IBabyAnimal<Butterfly>
{
public int NumberOfLegs { get;} = 100;
public Butterfly WillGrowToBe() => new Butterfly();
}
public class Butterfly : IGrownAnimal
{
public int NumberOfLegs { get; } = 0;
}
You can interact with every one of the animals as a simple IAnimal for things like leg count, and nicely, you can write something like this:
public static class Extensions
{
public static TGrown GrowUp<TGrown>(this IBabyAnimal<TGrown> baby)
where TGrown : IGrownAnimal
=> baby.WillGrowToBe();
}
Which you can then use against any baby animal to get the grown form.
If you want to distinguish baby animal (e.g. Pup) and adult one (Dog) you can implement 3 interfaces:
// Animal in the most general: all we can do is to count its legs
public interface IAnimal {
// get: I doubt if we should maim animals; let number of legs be immutable
int NumberOfLegs { get; }
}
// Baby animal is animal and it can grow into adult one
public interface IBabyAnimal : IAnimal {
IAdultAnimal WillGrowToBe()
}
// Adult animal can give birth baby animal
public interface IAdultAnimal : IAnimal {
IBabyAnimal Baby();
}
// Dog is adult animal, it can birth pups
public class Dog : IAdultAnimal {
public Dog()
public int NumberOfLegs { get; } => 4;
public Baby() => new Pup();
}
// Pup is baby animal which will be dog when grow up
public class Pup : IBabyAnimal {
public Pup()
public int NumberOfLegs { get; } => 4;
public WillGrowToBe() => new Dog();
}
I want to ask a question about C#, let me give you an example.
this is a a simple example, i have a IVehicle interface, it have a Name property. and then, there are a Car class and a MotorBicycle class, they are implement IVehicle too.
one day, there is a vehicle factory which is named 'RedFlag', all of thire products have a flag on it. so there is a IFlagVehicle interface, it has a FlagColor property. if thire products are car and motorbicycle, so we need another two class: FlagCar and FlagMotorBicycle.
the demo codes in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp9
{
#region Example
public interface IVehicle
{
string Name { get; }
}
#region Can't Changed This Region
public class Car : IVehicle
{
public string Name => "Car";
}
public class MotorBicycle : IVehicle
{
public string Name => "MotorBicycle";
}
#endregion
#region User Code
public interface IFlagVehicle : IVehicle
{
string FlagColor { get; }
}
public class FlagCar :
Car,
IFlagVehicle
{
public string FlagColor => "Red";
}
public class FlagMotorBicycle :
MotorBicycle,
IFlagVehicle
{
public string FlagColor => "Red";
}
#endregion
#endregion
class Program
{
static void Main(string[] args)
{
}
}
}
in this code, we can see, we must implement FlagColor property in two classes, and they are same in a lot of time.
but in C++, we can use a speicial template class, it use a template parameter as its BaseType, like this:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class IVehicle
{
public:
virtual string GetName() = 0;
};
class Car : public IVehicle
{
public:
virtual string GetName() override
{
return "Car";
}
};
class MotorBicycle : public IVehicle
{
public:
virtual string GetName() override
{
return "MotorBicycle";
}
};
class IFlagVechile
{
public:
virtual string GetFlagColor() = 0;
};
template < typename TBaseType >
class TFlagVechicle :
public TBaseType,
public IFlagVechile
{
public:
virtual string GetFlagColor() override
{
return "Red";
}
};
class FlagCar : public TFlagVechicle<Car>
{
};
class FlagMotorBicycle : public TFlagVechicle<MotorBicycle>
{
};
int main()
{
FlagMotorBicycle fmb;
cout << fmb.GetFlagColor() << " " << fmb.GetName() << endl;
return 0;
}
int this case, we can implement the GetFlagColor function in the same place for common implement of these classes.
so, i want to kown, is there any similar methods in C#? or I must change this design. if I must change this hierarchy, which is the best particle for this requirement in C#?
thank you!
One of challenges here is that the C++ template inherits from two classes which is not possible in C# (you can only implement multiple interfaces but not inherit multiple classes).
Note however that in OO languages, one should favor delegation over inheritance. In fact, delegating members between objects gives more flexibility, e.g. some members can be omitted, some members can be implemented conditionally etc.
One of options for you here then is the delegation, from the template to the private member the template creates for its own needs. It comes with a price of an additional constraint over the type that can be used as a template argument - the template has to create an instance and this can be constrained with the new constraint.
Note that the template delegates the IVehicle interface to the argument but it provides the implementation of the IFlagVehicle on its own.
class Program
{
static void Main(string[] args)
{
FlagMotorBicycle fmb = new FlagMotorBicycle();
Console.WriteLine("{0} {1}", fmb.FlagColor, fmb.Name);
Console.ReadLine();
}
}
public interface IVehicle
{
string Name { get; }
};
public class Car : IVehicle
{
public string Name { get; private set; }
public Car()
{
this.Name = "Car";
}
};
public class MotorBicycle : IVehicle
{
public string Name { get; private set; }
public MotorBicycle()
{
this.Name = "Bicycle";
}
};
public interface IFlagVechile
{
string FlagColor { get; }
};
public class TFlagVechicle<T> :
IVehicle, IFlagVechile
where T : class, IVehicle, new()
{
private T t;
public TFlagVechicle()
{
this.t = new T();
this.FlagColor = "Red";
}
public string FlagColor { get; private set; }
public string Name
{
get
{
return t.Name;
}
}
};
public class FlagCar : TFlagVechicle<Car>
{
};
public class FlagMotorBicycle : TFlagVechicle<MotorBicycle>
{
};
I have written a Collection like this:
class AnimalCollection<TValue> where TValue : Animal, new()
{
void Add(TValue value){};
void AddNew()
{
Add(new TValue());
}
}
I have some Classes which are derived from Animal:
class Animal
{
string Name;
}
class Fish : Animal
{
Fish(){};
}
class Mammal : Animal
{
Mammal(){};
}
As next i want to treat all collections the same way.
static void Main(string[] args)
{
var FishAquarium = new AnimalCollection<Fish>();
var MammalEnclosure = new AnimalCollection<Mammal>();
foo(FishAquarium);
foo(MammalEnclosure);
}
Question 1: I want to pass every AnimalCollection, which type need 'zoo'?
static void foo(AnimalCollection<Animal> zoo)
{
foreach(var animal in Zoo)
Console.WriteLine(animal.Name);
zoo.AddNew();
}
Question 2: What is the best practice to generalize a generic class?
Update:
More specific, i have a class which get any AnimalCollection.
class ZooController
{
public AnimalCollection<Animal> Animals{get; set;}
}
Generics would work:
static void foo<T>(AnimalCollection<T> zoo) where T : Animal, new()
{...}
However, it is usually not a good idea to roll your own collection types - it tends to create more confusion than it helps. You may want to consider justList<T>, or IList<T> at a push.
You say you don't want to use generics; that is IMO a silly decision since they solve exactly this problem, but you can also use covariance; if you have:
interface IAnimalCollection<out TValue> : IEnumerable<TValue>
{
void AddNew();
}
and:
class AnimalCollection<TValue> : IAnimalCollection<TValue>
where TValue : Animal, new()
{...}
then you can use:
static void foo(IAnimalCollection<Animal> zoo)
{
foreach (var animal in zoo)
Console.WriteLine(animal.Name);
zoo.AddNew();
}
and your code:
var FishAquarium = new AnimalCollection<Fish>();
var MammalEnclosure = new AnimalCollection<Mammal>();
foo(FishAquarium);
foo(MammalEnclosure);
will work fine; but - this is making work for no reason - simple generics via the foo<T> method shown above is simpler and more direct.
Try this approach:
class Program
{
static void Main(string[] args)
{
List<IAnimal> animals = new List<IAnimal>() { new Animal("Fuffy"), new Fish("Fishy"), new Mammal("Mommy") };
OutputAnimalsNames(animals);
}
private static void OutputAnimalsNames(List<IAnimal> animals)
{
foreach (IAnimal animal in animals)
{
Console.WriteLine(animal.Name);
}
}
}
public interface IAnimal
{
Guid Guid { get; }
string Name { get; }
}
public class Animal : IAnimal
{
public Guid Guid { get; private set; }
public string Name { get; set; }
public Animal(string name)
{
this.Name = name;
this.Guid = Guid.NewGuid();
}
}
public class Fish : Animal
{
public Fish(string name) : base(name)
{
}
}
public class Mammal : Animal
{
public Mammal(string name) : base(name)
{
}
}
I have the following classes:
//some base class
public abstract class MyObject<T>{
public static T FromObject(object anotherObject){
var t = Activator.CreateInstance<T>();
// some reflection logic here
return t;
}
}
public class Product: MyObject<Product>{
}
public class ProductCart: MyObject<ProductCart>{
public ICollection<Product> Products{get;set;}
}
public class Basket: ProductCart{
public int BasketId{get;set;}
}
public class Order: ProductCart{
public int OrderId{get;set;}
}
So now I could build my model like this:
var products = serviceContext.Products.Select(Product.FromObject).ToList(); // no problem here
var basket = Basket.FromObject(serviceContext.Basket); // problem is here - instance of ProductCart is returned
var order = Order.FromObject(serviceContext.Order); // same problem, instance of ProductCart
Is there a way somehow to solve it and get converted Basket and Order instead of base ProductCart?
The goal is:
var basket = Basket.FromObject(serviceContext.Basket); // return instance of Basket inherited from ProductCart
Thanks for helping.
If you can change the class definitions, you can pass along the type to ProductCart, like so:
public class ProductCart<T> : MyObject<T> { }
public class Basket : ProductCart<Basket> { }
public class Order : ProductCart<Order> {}
In your definition you tell Basket.FromObject to explicitly return ProductCarts (by inheriting from MyObject<ProductCart>).
And if you're unable to change the inherit tree, you can choose to hide the original method (or place it in a factory):
public class Basket : ProductCart
{
public int BasketId { get; set; }
public Basket FromObject(object anotherObject)
{
return MyObject<Basket>.FromObject(anotherObject);
}
}
That's because Basket is a MyObject<ProductCart>, and not a MyObject<Basket>.
If you don't want to redefine your hierarchy, you should define the return type of the static method according to the object you pass, like in this example:
using System;
public abstract class MyObject<T> {
public static TOtherObject FromObject<TOtherObject>(TOtherObject anotherObject) where TOtherObject : MyObject<T> {
var newOtherTypeInstance = Activator.CreateInstance<TOtherObject>();
// some reflection logic here
return newOtherTypeInstance;
}
}
public class ProductCart : MyObject<ProductCart> {
}
public class Basket : ProductCart {
public int BasketId { get; set; }
}
public class Order : ProductCart {
public int OrderId { get; set; }
}
class Program {
static void Main(string[] args) {
Order o = new Order();
var basket = Basket.FromObject(o);
}
}
Of course, at this point the actual implementation of the comment "some reflection logic here" could get much more complicated :)
The best practices are to program against the interface rather than the concrete class. I want to keep container of class that implements interface IPet. Does it correct? List<IPet> petList = new List<IPet>(); Or it's better to create an abstract class?
public interface IPet
{
string Name { get; set; }
void Introduce();
}
public class Parrot : IPet
{
public string Name { get; set; }
public Parrot(string name)
{
Name = name;
}
public void Introduce()
{
Console.WriteLine($"My name is {Name}. I am a parrot");
}
}
public class Cat : IPet
{
public string Name { get; set; }
public Cat(string name)
{
Name = name;
}
public void Introduce()
{
Console.WriteLine($"My name is {Name}. I am a cat");
}
}
PetShop petShop = new PetShop();
petShop.Add(new Cat("Garfield"));
petShop.Add(new Parrot("Kesha"));
Using interface in generics is the good choice!
Using abstract class force you to place any type in single chain of inheritance that can cause a problem with application evolution.
Besides, if you have a repeating behavoir you can create abstract class wich implements required interface, so you'll get advantages of both ways.
You can easily create an abstract class and put all repeating logic into it. Your classes look the same, only the Introduce() method is different, but you can use this.GetType().Name.ToLower() instead of "cat" and "parrot".
So, you can have the following:
public abstract class Pet : IPet
{
public string Name { get; set; }
protected Pet(string name)
{
Name = name;
}
public void Introduce()
{
Console.WriteLine($"My name is {Name}. I am a {this.GetType().Name.ToLower()}");
}
}
public class Cat : Pet
{
public Cat(string name)
: base(name)
{
}
}