Let's use a quite plain example with employees and company(-ies).
public abstract class Employee
{
// bunch of its features
}
public sealed class SalesManager : Employee
{
}
public sealed class SEO : Employee
{
}
Employee can take different posts or play different roles. So using inheritance (maybe with factory patterns in addition) doesn't give such a flexibility for concrete employee instance to change its role.
What would you advice, unfortunately I haven't seen the kind of approaches yet. And I haven't met a book which lights up the problem.
Edit
Thank you guys! In my edit I wanted to ask one more thing. Using generic role is it possible to transfer such a BLL to DAL. I have heard that generics are not supported in Entity Framework??
Thanks!
Use a has-a relationship
public class Employee
{
public Role EmployeeRole { get; set; }
}
public enum Role
{
SalesManager,
SalesPerson
}
Or you can make Role a class to store additional information in addition to the name of their role.
public class Role
{
public string Name { get; set; }
public decimal BaseSalary { get; set; }
}
To illustrate #Aasmund Eldhuset's comment:
public abstract class Role
{
public string Name { get; set; }
public decimal BaseSalary { get; set; }
public abstract void PerformRole();
}
public class SalesPerson : Role
{
public void PerformRole()
{
// Do something
}
}
Running with the idea of using a class, you can make it generic:
abstract class EmployeeRole { }
or
interface EmployeeRole { }
And have different types inherit from this abstraction:
class CEO : EmployeeRole { }
class SalesMgr : EmployeeRole { }
class Employee<T> where T : EmployeeRole
{
}
Then have a generic Factory implementation:
public Employee<T> MakeEmployee<T>() where T : EmployeeRole
{
}
Related
I have a base class for all the ENTITIES of my project which is inheriting from below model :
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
Now I have 1 another functionality which is common for so many modules and I want to keep BaseModel for that functionality and want it to be inherited from it.
Public class BaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Now our every model is suppose to inherit from BaseModel so inheriting from BaseNotice will be multiple inheritance.
Now I cannot like below :
Public class BaseNotice : BaseModel
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Because I would like to control functionality related to Notice from BaseNotice model and for notice I would like to keep BaseNotice as base model.
But I am not getting how to avoid multiple inheritance here and so what would be the proper way to design this?
There is No need to Multiple Inheritance. you can do that in this way:
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
public interface IBaseNotice
{
// Base Notices Contracts should be placed here
}
Public class BaseNotice: IBaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
public class ModelX:BaseModel
{
public IBaseNotice Notice { get ; set; }
public ModelX(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
Or you can use Second Generation of your BaseModel:
public class BaseModeNoticable:BaseModel
{
public IBaseNotice Notice { get ; set; }
public BaseModeNoticable(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
i'm have a hard and extreming question, how i'm may using FluentNHibernate for mapping a interface? follow a example below how i'm imagine do:
I'm have a interface:
public interface IUser
{
String Name { get; set; }
City City { get; set; }
}
and i'm have a class with implement this interface:
public class User : IUser
{
String Name { get; set; }
ICity City { get; set; }
}
Consider witch too exist a class for City and contains a property named Country and too exists at its interface...
I need to use FluentNHibernate to do the mapping as follows:
public class UserMap : ClassMap<IUser>
{
public UserMap()
{
Map(e => e.Name);
References<City>(x => x.City).Cascade.All();
}
}
public class CityMap: ClassMap<ICity>
{
public CityMap()
{
Map(e => e.Country);
}
}
It looks like mapping interfaces is supported:
It is perfectly acceptable for the named persistent class to be an interface. You would then declare implementing classes of that interface using the <subclass> element.
The <subclass> element's equivalent in Fluent NHibernate is SubclassMap<T>, I suppose. Therefore, although it's not clear what your actual problem is, can you try this instead:
public class UserMap : SubclassMap<IUser>
{
}
public class CityMap: SubclassMap<ICity>
{
}
It is clearly explained here how to achieve "multiple inheritance" in C# by using Interface. However, I wonder, how to achieve the same but in the Entity Framework Code First Workflow.
Provided code to make things clear :
public abstract class DomainObject {
// Every business model must have this fields
public Guid Id {get;set;}
public string SystemCode {get;set;}
}
And here also some optional abstract classes like:
public abstract class MultiTitleObject : DomainObject {
public string TitleRu { get; set; }
public string TitleEn { get; set; }
}
public abstract class ManageableByAdminObject : DomainObject {
public bool isVisibleOnSite {get;set;}
public bool isDeletedByAdmin {get;set;}
}
Let's say that I have class that need to have fields of both MultiTitleObject and ManageableByAdminObject and DomainObject as always rule.
Since C# doesn't support multiple inheritance, I can do the following :
public class ManageableByAdminDomainObject : ManageableByAdminObject {
}
public class ManageableByAdminMultiTitleDomainObject : ManageableByAdminDomainObject {
// Even here it's too complicated...
// What if I need to inherit from 3 or more classes?
}
So the solution I wanted to use is Interface like :
public interface IFieldImitation {
bool isVisibleOnSite ();
}
public class ManageableByAdminObject : IFieldImitation, DomainObject {
public bool isVisibleOnSite () => return true;
}
However, EF does understand abstract classes but not the interfaces.
How should I solve this problem?
Say I've got a simple inheritance chain where Employee is the abstract base class and Checkout and Manager inherit from it in this purely illustrative console app. Now I want to have a method that will take in an object of type Manager or Checkout and return an integer amount of a bonus depending on the position in the company of the employee. I had some initial thoughts on doing this, and would like to know potential long-term deficits or gains from each approach if this console app were to one day grow up to be a data-driven web application.
Use an interface common to the inherited classes.
My base class looks like
abstract class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
and my derived classes implement an interface designed to print employee information to the console called IPrintable and only has one method to do so. Although this interface has nothing to do with giving bonuses I mocked up the following in the class with my Main method lives and the program runs fine.
static int GiveBonusesViaInterface(IPrintable i)
{
if (i is Checkout)
return 1000;
else
return 2000;
}
It seems to me that if I wanted to use an interface for this I should probably make another one specific to giving raises instead of riding the coattails on an already-implemented interface (but that's another question for another day).
Use a static method in the base class like
public static int GiveBonus(Employee e)
{
if (e is Manager)
return 2000;
else
return 1000;
}
Make an abstract method in the abstract base class and nave derived classes implement as they see fit
abstract class Employee
//fields and constructors
{
public abstract int GiveBonusesViaAbstractMethod(Employee e);
}
This seems to be the worst idea to me because there will have to be a method in each derived class that takes in a parameter of IPrintable or Employee type and in the Manager class we'd have to test if the employee is-a Manager.
Are 1-2 equally as scalable and managable for a long-term web application? Is option 3 really as bad as I made it out?
You're missing the traditional OO way of doing this:
abstract class Employee {
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public abstract int GetBonusAmount();
}
class Manager : Employee {
public override int GetBonusAmount() { return 2000; }
}
class Checkout : Employee {
public override int GetBonusAmount() { return 1000; }
}
Console.WriteLine(someEmployee.GetBonusAmount());
I think you really have already answered your own question.
my derived classes implement an interface designed to print employee information to the console called IPrintable and only has one method to do so. Although this interface has nothing to do with giving bonuses
[emphasis mine]
You already have an interface for this. It's called Employee. The idiomatic way to do to this is to implement a virtual method on your abstract class and override if necessary. The more idiomatic C# approach is to write a property and override it. Like so:
abstract class Employee {
public virtual int GetBonus()
{
return this.Bonus;
}
public virtual int Bonus { get; set; }
}
class Manager : Employee {
public override int Bonus
{
get { return 2000; }
}
}
class Checkout : Employee {
public override int Bonus
{
get { return 1000; }
}
}
Implement a GetBonus() method in both the subclasses. You should avoid doing "is instance of" checks altogether.
I think abstract works well :
abstract class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public abstract int GetVariableBonus();
}
class Manager {
public int GetVariableBonus(){
return 2000;
}
}
class Employee{
public int GetVariableBonus(){
return 1000;
}
}
Is that what you need ?
I have system being developed for an HR system. There are Accountant employees and Programmer employees. For the first month of joining the company, the employee is not given any role. One employee can be an Accountant and a programmer at the same time. I have a design shown by the following code.
Now, I need to enhance the system by implementing a new functionality:
Terminate all Accountants. (Terminate means set status of employee as IsActive = false). The issue is I cannot set all accountants directly as inactive without checking. I need to check whether he has got any other role.
How to remodel these classes in order to do the terminate function more natural OO ?
UPDATE
I am looking for an answer that has EF Database First solution model and database schema for #AlexDev answer.
C# Code
List<Accountant> allAccountants = Get All accountants from database
public class Employee
{
public int EmpID { get; set; }
public DateTime JoinedDate { get; set; }
public int Salary { get; set; }
public bool IsActive { get; set; }
}
public class Accountant : Employee
{
public Employee EmployeeData { get; set; }
}
public class Programmer : Employee
{
public Employee EmployeeData { get; set; }
}
#AlexDev Answer
public class Employee
{
...
IList<Role> Roles;
bool isActive;
public void TerminateRole(Role role)
{
Roles.Remove(role);
if(Roles.Count == 0)
{
isActive = false;
}
}
}
public class Role
{
abstract string Name { get;}
}
public class ProgrammerRole : Role
{
override string Name { get { return "Programmer"; } }
}
REFERENCE
DDD Approach to Access External Information
Prefer composition over inheritance?
Inheritance vs enum properties in the domain model
Entity Framework: Get Subclass objects in Repository
To use the structure you are using you would need multiple inheritance for someone who is an accountant and a programmer, besides new roles might be added to the system, and that doesn't exist in C#. You should consider a different design. One possibility:
public class Employee
{
...
IList<Role> Roles;
bool isActive;
public void TerminateRole(Role role)
{
Roles.Remove(role);
if(Roles.Count == 0)
{
isActive = false;
}
}
}
public class Role
{
abstract string Name { get;}
}
public class ProgrammerRole : Role
{
override string Name { get { return "Programmer"; } }
}
Then you can subclass Role for each type, and you can decide to terminate just one role, or all of them.
I'm writing a new answer since from the schema you added to the question I'm assuming you won't be subclassing Role. Also if you are using NHibernate don't forget to use public virtual properties.
public class Employee
{
...
public virtual IList<Role> Roles { get; set; }
public virtual bool isActive { get; set; }
public virtual void TerminateRole(Role role)
{
Roles.Remove(role);
if(Roles.Count == 0)
{
isActive = false;
}
}
}
public class Role
{
public virtual int RoleID { get; set; }
public virtual string Name { get; set; }
}
And mappings:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.EmpId);
Map(x => x.JoinedDate)
Map(x => x.Salary);
Map(x => x.IsActive);
HasManyToMany(x => x.Roles).Cascade.AllDeleteOrphan().Table("EmployeeRole")
}
}
public class RoleMap : ClassMap<Role>
{
public RoleMap()
{
Id(x => x.RoleID);
Map(x => x.RoleName);
}
}
public abstract class AbstractEmployee
{
...
public abstract bool IsActiveAccountant { get; set; }
public abstract bool IsActiveProgrammer { get; set; }
public bool IsActive() { get { return bitwise or of all roles; } }
}
public class NewEmployee : AbstractEmployee
{
...
public override bool IsActiveAccountant { get; set; }
public override bool IsActiveProgrammer { get; set; }
}
public class Programmer : AbstractEmployee
{
...
public override bool IsActiveAccountant { get; set; }
public override bool IsActiveProgrammer { get; set; }
}
Cons:
with every new system-wide role added you have to modify classes
Pros:
you dont need to search for accountants
programmers can have empty implementation of IsActiveAccountant, because this role is inactive for them anyway
NewEmployee can have many roles at the same time
If overhead from introducing new roles is significant, I would stick with searching
From my answer in Prefer composition over inheritance?
I will first start with the check - whether there exists an "is-a" relationship. If it exists I usually check the following:
Whether the base class can be instantiated. That is, whether the base class can be non-abstract. If it can be non-abstract I usually prefer composition
E.g 1. Accountant is an Employee. But I will not use inheritance because a Employee object can be instantiated.
E.g 2. Book is a SellingItem. A SellingItem cannot be instantiated - it is abstract concept. Hence I will use inheritacne. The SellingItem is an abstract base class (or interface in C#)