1

I'm defining an Interface to group two different subclasses. Each class implements the inherit method but each needs different parameters to be able to work.

Here's the interface.

public interface Billable()
{
   decimal Bill();
}

Here's the first class

public class HourlyEmployee : Billable
{
   public decimal Bill(int hoursWorked, decimal pricePerHour) { }
}

Here's the second

public class CommissionEmployee : Billable
{
   public decimal Bill(decimal commisionPercentage) { }
}

As you can see, conceptually they use the method to achieve the same, which is charging for a service. That's why I initially thought about inheritance, but it seems that's not the best approach.

What other alternatives can make the classes relate to each other?

RaulMonteroc
  • 176
  • 14
  • Define the signature of your method as *public decimal Bill(int base, decimal rate)*. This pattern of returning an *extensive* quantity as the product of a different *extensive* quantity times an *intensive* quantity is a common place pattern. – Pieter Geerkens Sep 17 '14 at 03:29
  • I do not think trying to include all the required parameters in the Interface method signature is a good idea, that will make the interface brittle. – BuddhiP Sep 17 '14 at 04:08

3 Answers3

3

This doesn't directly answer the question in your title, but you did ask for other alternatives...

Your interface is a contract, guaranteeing that your classes will have a Bill() function that returns a decimal. But that doesn't mean you have to accept the parameters in that method.

Here the constructors for each class accept the parameters. The Bill() method does the calculation to return the appropriate value.

public interface IBillable
{
    decimal Bill();
}

public class HourlyEmployee : IBillable
{
    private int hoursWorked;
    private decimal pricePerHour;

    public HourlyEmployee(int hoursWorked, decimal pricePerHour)
    {
        this.hoursWorked = hoursWorked;
        this.pricePerHour = pricePerHour;
    }

    public decimal Bill()
    {
        return hoursWorked * pricePerHour;
    }
}

public class CommissionEmployee : IBillable
{
    private int commissionPercentage;

    public CommissionEmployee(int commissionPercentage)
    {
        this.commissionPercentage = commissionPercentage;
    }

    public decimal Bill()
    {
        // do some calculation using commissionPercentage and return a value...
    }
}
Grant Winney
  • 65,241
  • 13
  • 115
  • 165
2

Not sure if this is the best approach, but I think your approach of using an interface is good (which I'd call IBillable by convention).

But you should not try to accommodate all the required values for the calculation as parameters in the interface method, as this limits your extensibility, what if you come across a new kind of employee who needs one more value for bill calculation. Interface is a contract which should not change, hopefully ever. Method suggested below doesn't have that problem.

One suggestion is to use another class (let's say BillCalculator) and move the different parameters required by the Billable interface to properties of that class.

public abstract class BillCalculator: IBillable 
{
    abstract decimal Bill();
}

public class HourlyBillCalculator: BillCalculator
{
   public int HoursWorked { get; set; }
   public decimal PricePerHour { get; set; }

   public HourlyBillCalculator(int hoursWorked, decimal pricePerHour) 
   {
      HoursWorked = hoursWorked;
      PricePerHour = pricePerHour;
   }

   public override Bill() 
   {
      // Calculate the Bill
   }
}

public class CommisionBillCalculator: BillCalculator {
     public decimal CommisionRate { get; set; }

     public CommisionBillCalculator(decimal rate)
     {
         CommisionRate = rate;
     }

     public override Bill() {
          // Calculate the Bill
     }
}

Corresponding Calculator class has to be instantiated using a factory pattern or something to fit the need. Then it's just a matter of calling the Bill method, which will use the instance properties to calculate the value.

That will let you keep interface signature consistent.

Note: Syntax may be off, but hope you get the idea.

BuddhiP
  • 6,231
  • 5
  • 36
  • 56
  • Cool. Glad I could help. Grant's answer suggests the same technique so that's good. He builds it into the same Employee classes, where I used a separate class, a minor difference, but I still think it's better to take Billing away from the Employer class as we will need to bill over and over for the same Employee. – BuddhiP Sep 17 '14 at 04:06
0

Obviously what you propose produces a syntax error as every implementation of the interface should implement all its prototyped methods. By definition, implementing a prototype means having the same parameters, that's why you cannot have multiple parameters for the same method. However, you can take the advantage of the optional parameters introduced in .NET 4.0

So you can have something like this.

Community
  • 1
  • 1
yazanpro
  • 4,512
  • 6
  • 44
  • 66