Search code examples
c#oopdesign-patterns

How can I implement the inheritance and interface correctly to the objects which had the some same properties C#


I have two types of employees (contractors and permanent staff). I tried to retrieve contractors whose contract end date is within a year. I noticed the code smell.

using System;

namespace Employee.Model
{
    public class IEmployee
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public DateTime ContractEndDate { get; set; }
    }
}

Test

namespace Employee.Tests
{
    public class EmployeeTests
    {

        public static IEmployee SampleData = new[]
        {
            new IEmployee { Id = 1, Name = "permanent staff 1" },
            new IEmployee { Id = 2, Name = "contractor 1", ContractEndDate = new DateTime(2025, 12, 30) },
            new IEmployee { Id = 3, Name = "permanent staff 2" },
            new IEmployee { Id = 4, Name = "contractor 2", ContractEndDate = new DateTime(2027, 12, 30) }
        };


        [Test]
        public void Contract_Matched()
        {
            // Expected Data
            int countEndWithin2Years = 1;

            // Test
            var testCount = ECalculator.GetEndWithinXYears(EmployeeTests.SampleData);

            //Asset
            Assert.That(countEndWithin2Years, Is.EqualTo(testCount));
        }

        
    }

I tried to rewrite it

    public interface IPermanent
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Permanent : IPermanent
    {
        private int id;
        private string name;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

    public interface IContractor: IPermanent
    {
        public DateTime ContractEndDate { get; set; }        
    }

    public class Contractor : IContractor
    {
        private int id;
        private string name;
        private DateTime contractEndDate;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public DateTime ContractEndDate
        {
            get { return contractEndDate; }
            set { contractEndDate = value; }
        }

    }

    public interface IEmployee : IPermanent, IContractor
    {
    }

And I amended the test case

        public static IEnumerable<IEmployee> SampleData = new[]
        {
            (IEmployee)new Permanent { Id = 1, Name = "permanent staff 1" },
            (IEmployee)new Contractor { Id = 2, Name = "contractor 1", ContractEndDate = new DateTime(2025, 12, 30) },
            (IEmployee)new Permanent { Id = 3, Name = "permanent staff 2" },
            (IEmployee)new Contractor { Id = 4, Name = "contractor 2", ContractEndDate = new DateTime(2027, 12, 30) }
        };


        [Test]
        public void Contract_Matched()
        {
            // Expected Data
            int countEndWithin2Years = 1;

            // Test
            var testCount = ECalculator.GetEndWithinXYears(EmployeeTests.SampleData);

            //Asset
            Assert.That(countEndWithin2Years, Is.EqualTo(testCount));
        }

However, it is not working because I implemented the inheritance and interface wrongly, creating a casting problem. Please suggest how I can implement OOP correctly for above?

Thanks


Solution

  • These different employees are similar to the Employee class.

    Instead, you can create new Employee types that inherit methods and data from the Employee class created. These new classes can extend the Employee class with the specific behavior needed for each type:

    Each of these classes inherits the shared behavior from their base class, the Employee class. Add the implementations or properties for new and different functionality in each derived class. These derived classes already have all the behavior defined in the Employee class.

    public abstract class Employee
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    }
    
    public class Permanent : Employee
    {
        public Permanent(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
    
    public class Contractor : Employee
    {
        public DateTime ContractEndDate { get; set; }
    
        public Contractor(int id, string name, DateTime contractEndDate)
        {
            Id = id;
            Name = name;
            ContractEndDate = contractEndDate;
        }
    }
    
    public static class ContractCalculator
    {
        public static int GetNumberOfContractEnd(IEnumerable<Employee> employees, int expiredInYears)
        {
            
            employees = employees.Where(a => a is Contractor).ToList();
    
            var contractors = new List<Contractor>();
            foreach (var contractor in employees)
            {
                contractors.Add((Contractor)contractor);
            }
    
           return contractors.Where(a => a.ContractEndDate <= DateTime.Now.AddYears(expiredInYears)).Count();
        }
    
    
    }
    
    public class BucketTests
    {
        public static List<Employee> SampleData = new List<Employee>()
            {
                new Permanent(1, "Permanent 1"),
                new Contractor(1, "Contractor 1", new DateTime(2036, 12, 30)),
                new Permanent(2, "Permanent 2"),
                new Contractor(2, "Contractor 2", new DateTime(2024, 12, 30)),
                new Permanent(3, "Permanent 3"),
            };
    
        [Test]
        public void Bucket_Matched()
        {
    
            var count = ContractCalculator.GetNumberOfContractEnd(BucketTests.SampleData, 2);
            
            //Asset
            Assert.That(count, Is.EqualTo(1));
            
        }        
    }
    

    We have Permanent and Contractor inherit from Employee; simple and nice.

    Microsoft provides a perfect example of learning OOP as below.

    OOP Example by Microsoft