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 4 years ago.
Improve this question
I'm trying to understand when I should use an interface vs an abstract class. I was looking at improving my MVC application design and came across this article: http://www.codeproject.com/Articles/822791/Developing-MVC-applications-using-SOLID-principles
In the section about OCP the author gives an example about calculating the price of books. The original code looks like this:
enum Category
{
student,
corporate
}
class Book
{
public double CalculatePrice(double price,Category category)
{
if (category == Category.corporate)
{
price = price- (price * 10);
}
else if (category == Category.student)
{
price = price - (price * 20);
}
return price;
}
}
And his solution looks like this:
abstract class Book
{
public abstract double CalculatePrice(double price);
}
class StudentBook : Book
{
public override double CalculatePrice(double price)
{
return price - (price * 20);
}
}
class CorporateBook : Book
{
public override double CalculatePrice(double price)
{
return price - (price * 10);
}
}
My questions while looking at this solution are:
Why use an abstract class here instead of an interface?
What difference would it make if you were to change this to an interface? Would it really matter?
Thanks for any help in understanding this
The example is artificial because the Book base class has no behaviour, it could just as well be an interface. However a more realistic example would have many other methods such as
getAuthor()
getISBN()
isFiction()
and presumably those behaviours do not change if the book is Student or Corporate so we have a base class with lots of standard behaviours. So Book would genuinely be a Class in that it has useful behaviours that are shared by its derived classes.
Things get a bit more complicated when you have several groups of behaviours, for example a Library Book is a Book but it is also a LendableThing and in Java you can't inherit from two different base classes.
In practice I find that have more Interfaces than I do Abstract Base classes. I define Interfaces as my outward facing contract. That is I write some code that works on objects that my callers give me. I tell them I need something that fulfils this Interface. I don't make any statement about how that is done, just give me something that can CalculatePrice.
The AbstractClass is more for the benefit of someone implementing some code. We're effectively giving a partially written class and then asking the coder to "fill in the blanks". Situations where we can usefully do that tend to be more rare.
An interface is probably the best option in the example you have given, though that may change if the example is expanded.
Broadly speaking, both interfaces and abstract classes can be used to enforce contracts - ie., that a type implementing the contract should behave a certain way. The main difference is that an interface just says what the implementing type should be able to do, whilst abstract classes have the ability to share functionality in addition to a contract.
Your book example could be extended to have extra functionality that has the same implementation across all types of Book, and in that case, you would want to use an abstract class. For example, if I wanted to share an getISBN() method, but the implementation didn't change across the types implementing the contract, then it might make more sense to use an abstract class.
The limitation being that you can only ever implement a single abstract class on any given type but you may implement as many interfaces as you like.
I've seen a few examples where an abstract class implements an interface, and the concrete class implements the abstract class - This way, you get the best of both worlds; 3rd parties don't have to be coupled to your implementation of getISBN() on the abstract class.
Another tangential point is that some mocking libraries will struggle with mocking non-virtual methods and this includes methods on abstract classes - however, they will work perfectly fine with interfaces.
As a TLDR: interfaces are for types where you are not at all interested in how the implementation is done and you only care that a type has certain features. Use abstract classes when you care about how certain parts of the class are implemented but not others.
In your case it would be more suitable using an interface rather than an abstract class. I say so, because you don't provide any implementation of your method that later may be overidden by the classes that inherit your abstract class. All you want it that either a CorporateBook and StudentBook have a method called CalculatePrice with the same signature. Hence, you could define an interface called
public interface IPriceCalculator
{
public double CalculatePrice(double price);
}
and later just make your classes implement this interface:
class StudentBook : Book, IPriceCalculator
{
public double CalculatePrice(double price)
{
return price - (price * 20);
}
}
and
class CorporateBook : Book, IPriceCalculator
{
public override double CalculatePrice(double price)
{
return price - (price * 10);
}
}
On the other hand I would suggest another approach for calculating the value:
public interface IPriceCalculator
{
public double CalculatePrice(double price);
}
public class PriceCalculator
{
public double Discount { get; private set; }
public PriceCalculator(double discount)
{
Discount = discount;
}
public double CalculatePrice(double price)
{
return price - (price*Discount)
}
}
and later inject an object of type IPriceCalculator to the Book constructor.
public class Book
{
// The initial price.
public double Price { get; private set; }
public IPriceCalculator PriceCalculator { get; private set; }
public Book(double price, IPriceCalculator priceCalculator)
{
Price = price;
PriceCalculator = priceCalculator;
}
public double CalculatePrice()
{
return PriceCalculator.CalculatePrice(Price);
}
}
Last,
class StudentBook : Book
{
public StudentBook(double price, IPriceCalculator priceCalculator) :
base(double price, IPriceCalculator priceCalculator)
{
}
}
class CorporateBook : Book
{
public CorporateBook(double price, IPriceCalculator priceCalculator) :
base(double price, IPriceCalculator priceCalculator)
{
}
}
and you create the PriceCalculator of your choice and pass them to the constructors of StudentBook and CorporateBook.
In C#, the difference between using an abstract class versus an interface is mostly about the limitation on polymorphism in CLS languages. In the example that you have given, because the two implementations of CalculatePrice are very simple, using an abstract class instead of an interface adds the polymorphism constraint to all derivatives of Book and brings almost no gain.
I understand that this is a highly simplified example, but hopefully the book will show how the calculation of the price of the book doesn't belong inside the book at all. The first principle of S.O.L.I.D. is Single Responsibility. It is by far the most important. The book class (and derivatives) calculating its price adds a second responsibility to the book (I'm assuming that containing content is the other, and primary, responsibility of the book). This violates the first principle. [It also violates other OOP "rules" like high class cohesion, but that is another topic].
If you wanted to provide access to the calculation of the price to the book class, you would make use of a separate calculating class in the book:
public interface IBookPriceCalculator
{
double CalculatePrice(double price);
}
public class StudentBookPriceCalculator : IBookPriceCalculator
{
public double CalculatePrice(double price)
{
return price - (price * 0.20);
}
}
public class StudentBook
{
IBookPriceCalculator _priceCalculator;
public StudentBook()
{
_priceCalculator = new StudentBookPriceCalculator();
}
public double BasePrice { get; set; }
public double GetPrice()
{
return _priceCalculator.CalculatePrice(BasePrice);
}
}
The answer depends of some factors like common behaviors and level of extensibility. I'm going to explain it creating here an imaginary concept of social network so for us a social network is something that can post messages with images and save an history of posted messages. Then our social networks will share behavior so I will create a base class (abstract class).
public abstract class SocialNetwork
{
public List<string> History { get; private set; }
protected SocialNetwork()
{
History = new List<string>();
}
public void Post(string comment, byte[] image)
{
DoPost(comment, image);
History.Add(comment);
}
protected virtual void DoPost(string comment, byte[] image)
{
}
}
Now I will create our social networks: facebook and twitter
public class Facebook : SocialNetwork
{
protected override void DoPost(string comment, byte[] image)
{
//Logic to do a facebook post
}
}
public class Twitter : SocialNetwork
{
protected override void DoPost(string comment, byte[] image)
{
//Logic to do a twitter post
}
}
Everything look fine until now. Well, imagine we have to handle a totally different kind of social network, for instance some social network that not store messages history, something like Snapchat:
public class Snapchat : SocialNetwork
{
private string _lastMessage;
protected override void DoPost(string comment, byte[] image)
{
//Logic to do a snapchat post
_lastMessage = comment;
ProcessLastMessage();
History.Clear();
}
private void ProcessLastMessage()
{
//Some logic here.
}
}
As you can note above the Snapchat class inherits from SocialNetwork class so Snapchat class will store a history of posts too. But we don’t want it so we have to put code to clear the history list.
Interfaces comes in action
The problem with the implementation above is Snapchat have a thing he don’t need i.e the History so we need a higher level of abstraction here, SocialNetwork base class is what we know how a normal social network, but we need a super abstraction to define what a SocialNetwork do without define any behavior for it so we need define an interface.
public interface ISocialNetwork
{
void Post(string message, byte[] image);
}
Now we will do SocialNetwork class to implement ISocialNetwork:
public abstract class SocialNetwork : ISocialNetwork
{
...
public void Post(string comment, byte[] image)
{
...
}
...
}
Now here is the new Snapchat class:
public class Snapchat : ISocialNetwork
{
private string _lastMessage;
public void Post(string message, byte[] image)
{
//Logic to do a snapchat post
_lastMessage = message;
ProcessLastMessage();
}
private void ProcessLastMessage()
{
//Some logic here.
}
}
Now the design is powerfull enough. Facebook and Twitter share common behavior from SocialNetwork (abstract class) and it implements ISocialNetwork (interface). Snapchat class not share any behavior with Facebook and Twitter but it is a social network too so it implements directly ISocialNetwork interface.
You can read the full article from here: http://www.theagilethinker.com/2015/08/22/an-interesting-example-of-convivence-between-abstract-classes-and-interfaces/
Related
Could someone, please, explain why an answer in this question advocates usage of extension methods while defining base interfaces.
- Why not including the the SteerLeft() and Stop() methods in their respective interfaces? - Is it to illustrate adding behaviors that should not/could not be anticipated/forced by the "base"?
- Isn't it better to "force" something as basic as "steering" behavior when you're requiring a steering wheel?
Below, I've extracted relevant code. The answering person states:
you could use the Extension Methods feature added to C# 3.0 to
further simplify calling methods on those implied properties
public interface ISteerable { SteeringWheel wheel { get; set; } }
public interface IBrakable { BrakePedal brake { get; set; } }
public class Vehicle : ISteerable, IBrakable
{
public SteeringWheel wheel { get; set; }
public BrakePedal brake { get; set; }
public Vehicle() { wheel = new SteeringWheel(); brake = new BrakePedal(); }
}
public static class SteeringExtensions
{
public static void SteerLeft(this ISteerable vehicle)
{
vehicle.wheel.SteerLeft();
}
}
public static class BrakeExtensions
{
public static void Stop(this IBrakable vehicle)
{
vehicle.brake.ApplyUntilStop();
}
}
public class Main
{
Vehicle myCar = new Vehicle();
public void main()
{
myCar.SteerLeft();
myCar.Stop();
}
}
The point of using extension method is that you can add method to an existing .Net class even if you do not have the Source code or it reside within different assembly.
And extension method helps to
These methods can be added later (than type authoring time) after type has already been published.
Extension methods can target interfaces.
Different people can extend the same type differently as per their needs.
Take LINQ for example it provides Methods that work on any IEnumerable type!
EM are not some substitute of multiple inheritance and is not an inheritance mechanism. It's just a tool, like name suggests, to extend functionality of some type by your means.
In this concrete code there is no much sense of using EM. As you noted, you can easily extend functionality of the class, just by adding a new method inside its body.
EM are extremely useful in cases when you can not change original source of a class or not allowed to do so.
In many books or articles u may see such a definition about interface :an interface is a "contract" or an agreement between the consumer (caller) and the provider (callee).but Unfortunately there is no Clear example that describes what is caller class or what is callee class and show how they could communicate with each other through interface.
from this point of view I am confused about The Terms caller(consumer) and callee (provider), I just know that we define an interface and a class Implements that Interface . is the implementor class considerd as caller if so what about callee , how callee uses the interface , could any one describe this terms clarely and give a clear example about that .
any help would be highly appreciated .
Who implements an interface is a callee, cause he provides an implementation of interface. Consumer is tat one who uses an object of the callee, so they call it caller.
EDIT
pulbic interface IPlugin
{
double Calculate(double d1, double d2);
}
public class WebConnectPlugin: IPlugin
{
public double Calculate(double d1, double d2){ // some code}
}
public class DBConnectPlugin: IPlugin
{
public double Calculate(double d1, double d2){ // some code}
}
and somewhere in the code:
public class CallerIDE
{
IPlugin plugin= null;
public void DoSomething()
{
contractor = GetPlugin();
double value = contractor.Calculate(10.3456, -3.546456);
}
private IPlugin GetPlugin()
{
return new WebConnectPlugin();
return new DBConnectPlugin(); //based on some logic
}
}
SCHOOL is place where many INDIVIDUALS come and study. Every INDIVIDUAL has different way of learning.
SCHOOL has one rule : any INDIVIDUAL coming in must be LEARNABLE.
SCHOOL is sure that if an INDIVIDUAL is not LEARNABLE then it can not teach them and hence
they cant study.
Every INDIVIDUAL implements ILEARNABLE interface
public class INDIVIDUAL : ILEARNABLE //this is provider class as it provides implementation of interface.
{
LEARN()
{
//WAY OF LEARNING IS MENTIONED HERE...
}
}
School teaches them through a method called Teach()
class SCHOOL // This is consumer class -
{
void Teach (ILEARNABLE anyone)
{
...
anyone.LEARN();
... some code...
}
}
Here school does not have to worry about who is individual as long as they have implemented ilearnable interface.
The caller would be the code that calls the thing that implements the interface. The Callee would be an object that implements an interface. Although people rarely use this terminology.
Here's an example in (java-inspired) pseudocode:
interface readable {
function read();
}
//callee
class book implements readable {
function read() {
print this.text;
}
//other implementation code goes here
}
//caller
define readable b = new book();
b.read();
I am making a payment system for my site. Users can select one of several payment providers to pay, but all should behave in the same way. I thought to represent this behavior like this:
public abstract class PaymentProvider {
private static var methods = Dictionary<String,PaymentProvider>
{
{"paypal",new PaymentProviderPaypal()},
{"worldpay",new PaymentProviderWorldpay()}
}
public static Dictionary<String,PaymentProvider> AllPaymentProviders
{
get {return methods;}
}
public abstract pay();
}
public class PaymentProviderPaypal : PaymentProvider {
public override pay() {
}
}
public class PaymentProviderWorldpay : PaymentProvider {
public override pay() {
}
}
You are supposed to use this by writing PaymentProvider.AllPaymentProviders["key"].pay(). The idea is that the functions using this class don't need to know about how the underlying payment provider is implemented, they just need to know the key.
However, at the moment, if you have access to the PaymentProvider class, you also have access to the inheriting classes. Its possible to instantiate a new copy of the inheriting classes, and make use of them in an unexpected way. I want to encapsulate the inheriting classes so that only the abstract PaymentProvider knows about them.
How should I do this? Different protection levels like protected don't work here - In Java, protected means that only other classes in the namespace can use that class, but in C# it means something else.
Do I have the right idea here? Or should I use a different method?
A couple of options spring to mind:
Put this in a separate assembly from the client code, and make the implementations abstract
Put the implementations inside the PaymentProvider class as private nested classes. You can still separate the source code by making PaymentProvider a partial class - use one source file per implementation
The first option is likely to be the cleanest if you don't mind separating the clients from the implementation in terms of assemblies.
Note that both of these are still valid options after the change proposed by Jamiec's answer - the "visibility" part is somewhat orthogonal to the inheritance part.
(As an aside, I hope the method is really called Pay() rather than pay() :)
Your inheritance heirachy is a bit wonky, I would be tempted to do it a similar but crucially different way.
public interface IPaymentProvider
{
void Pay()
}
// Implementations of IPaymentProvider for PaypalPaymentProvider & WorldpayPaymentProvider
public static class PaymentHelper
{
private static var providers = Dictionary<String,IPaymentProvider>
{
{"paypal",new PaymentProviderPaypal()},
{"worldpay",new PaymentProviderWorldpay()}
}
public static void Pay(string provider)
{
if(!providers.Containskey(provider))
throw new InvalidOperationException("Invalid provider: " + provider);
providers[provider].Pay();
}
}
Then the usage would be something like PaymentHelper.Pay("paypal").
Obviously if there is more data to provide to the Pay method this can be added to both the interface, and the helper. for example:
public interface IPaymentProvider
{
void Pay(double amount);
}
public static void Pay(string provider, double amount)
{
if(!providers.Containskey(provider))
throw new InvalidOperationException("Invalid provider: " + provider);
providers[provider].Pay(amount);
}
I'm looking to learn how to use interfaces and base classes effectively. I'm not exactly sure where to put common properties? Do only behaviors belong in an interface? If properties such as: Color and MinSpeed shouldn't go in the interface, where should they live? In an abstract class?
public interface IVehicle
{
void Speed();
void Clean();
void Stop();
}
public class Bmw : IVehicle
{
// Because these pertain to every vehicle no matter of maker,
// should these propertes go in the interface? Or in an abstract class?
public string Color { get; set; }
public int MinSpeed { get; set; }
#region IVehicle Members
public void Speed()
{
}
public void Clean()
{
}
public void Stop()
{
}
#endregion
}
Interfaces can be thought of as a contract that must be satisfied by any implementing class. Use it if you want to guarentee that all classes do the same thing—satisfy the same API—but you don't care how they do it. If properties are a part of that API, then by all means include them in your interface.
From your example above, if you want all cars to be guaranteed to have a color and minSpeed, then those properties belong in the interface. If those properties are specific to BMWs alone, then they belong in the BMW class. If those properties belong to some classes but not others, you could create a new interface extending the original one:
public interface IVehicleWithColorAndMinSpeed : IVehicle
{
string Color { get; set; }
int MinSpeed { get; set; }
}
(just don't get carried away with this)
Abstract classes are similar, but allow you to provide a default implementation for your sub classes.
Abstract classes tend to be easier to version, since you can add something new to your API, and provide a default implementation that your existing subclasses will automatically pick up; adding something to an interface immediately breaks all existing classes which implement that interface.
The 'right' answer is entirely dependent on your domain model. What is the problem you're trying to solve? There is no 'right' answer other than the one which solves the particular problem at hand with the greatest:
understandability
maintainability
brevity
isolation
performance
You can probably consider most of those properties to be in order of importance, but they mean different things to different people and there's probably a lot of debate implied there too.
Can you tell us any more about the particular application you imagine these classes to serve?
I have 3 classes, two inherit from 1:
public class Employee {
private virtual double getBonus() { ... }
private virtual double getSalary() { ... }
}
public class Nepotism : Employee {
private double getBonus() { ... }
}
public class Volunteer : Employee {
private double getSalary() { ... }
}
So the question is sometimes there will be a Volunteer who gets the Nepotism bonus - is there some way to write the constructors to allow overriding/nesting the base class like this:
Employee Bill = new Volunteer(new Nepotism());
I'm thinking something like:
public class Volunteer : Employee {
private Employee _nest;
public Volunteer(Employee nest)
: base() {
_nest = nest;
// now what?
}
}
Basically I want some objects to have the overrides from both classes.
I would like to avoid writing the override methods to check for nested classes.
getSalary() {
return (nest != null) ? nest.salary : salary; // I want to avoid this if I can
}
How can I do this? Am I on the right track? Am I off the rails?
Instead of subclassing, you might want to consider using the Decorator Pattern.
It provides an alternative to subclassing, and it useful when you may need to add "multiple" pieces of additional functionality to a single instance of a class, which is exactly the scenario.
I think you are trying to use inheritance in an ill-advised way. This approach creates a mess of dependences and oddball business rules, which results in a rigid architecture that is hard to use and maintain.
If calculating an employees salary is dependent upon the Employee as well as "bonus traits", then it would be better to separate all three things from each other:
interface IBonusTrait
{
decimal ApplyBonus(Employee employee, decimal currentTotal);
}
class Employee
{
// ...
public decimal BaseSalary { get; set; }
public IList<IBonusTrait> BonusTraits { get; set; }
}
class SalaryCalculator
{
public decimal CalculateSalary(Employee employee)
{
decimal totalSalary = employee.BaseSalary;
foreach (IBonusTrait bonusTrait in employee.BonusTraits)
{
totalSalary = bonusTrait.ApplyBonus(employee, totalSalary);
}
return totalSalary;
}
}
If an object can be both classes at once, then you may need to rethink how you're doing your inheritance.
It seems to me that if a Volunteer can sometimes get a Nepotism bonus, then really, your Volunteer class should have a getBonus() method, and this method really belongs in the base class. It would return zero for most volunteers, but occasionally it wouldn't - there's nothing wrong with that.
Reed Copsey already said, that Decorator Pattern is something to consider.
There is also this youtube video which is very similar to your case (John Skeet is presenting it).