Related
Currently, am working on architecture of application, I have many entities in my project i.e student teacher university, I was wondering about is it a good practice that all entity must implement interface. This will help me in dependency injection? What is the best practice from architecture point of view.
public interface IMyEntity
{
//an empty interface
}
public class Student:IMyEntity
{
}
public class Teacher:IMyEntity
{
}
//hi I can deal with every object which implement IMyEntity
void Display(IMyEntity entity) //this function can be in some class
{
// if IMyEntity is teacher behave like a teacher
// if IMyEntity is student behave like sutdent
}
I know interface is a contract, but from architecture point of view it is best practice? I know my IMyEntity interface is empty.
Not necessarily. If in this case Student and Teacher have some common functionality then a shared interface would be one approach to take.
public void Display(IUniPerson person)
{
var name = person.Name; // Everyone, student or teacher, has a name
...
}
However, the example you give seems to suggest that this is not the case, and the Display method will attempt to treat the passed in instance of IMyEntity differently depending on it's type. In that case, you may be better with 2 Display methods with different parameters.
public void Display(ITeacher teacher) { // teacher processing }
public void Display(IStudent student) { // student processing }
tl:dr version: implement an interface across multiple classes if it makes sense for those classes to implement related methods and functions, rather than just as a blanket rule.
I think that decoupling 2 or more classes is a good taste in terms of developing and it really helps maintaining the code in a long run.
Consider the follow scenario:
static void Main(string[] args)
{
var objA = new A();
var objB = new B(objA);
}
public class A {}
public class B
{
public B(A obj)
{
//Logic Here
}
}
The problem with this code it's that it's strongly coupled, class B needs class A to be instanced and do it's business.
This is not a problem if you are sure that B is never going to have some drammatic change.
Now if we want to decouple it we can make a first improvement implementing an interface like
static void Main(string[] args)
{
var objA = new A();
var objB = new B(objA);
}
public interface IA()
{
//TODO
}
public class A : IA {}
public class B
{
public B(IA obj)
{
//Logic Here
}
}
It looks quite better what we still have a couplation problem in the Main, so at this point we will have to implement a Dependency Injection with a IOC like Ninject, and our code will be like to something like:
static void Main(string[] args)
{
var objB = new B();
}
public interface IA()
{
//TODO
}
public class A : IA {}
public class B
{
public B(IA obj)
{
//Logic Here
}
}
Yes, that looks good. We have completely removed the couplation problem and it will be quite easy if in the future we just need to take A, delete it and replace it wich something new more cool.
Obviously overkilling it's a bad practice and I belive DI must be used only after carefuly planning to avoid useless implementations.
For example if I have a class C which has some basic operations, and I am sure that it will never change or have some drammatic need to update i can avoid DI.
So do you have to implement interfaces on every model in your project?
Well I don't think each model in your project needs to implements an interface or DI, just think about it and see where it can be useful and where it's just overkilling.
Looking at how .NET solved this, you can see some ambiguity.
For instance for every object has a function where you can ask for a string representation of the object: ToString(), even though for a string representation might not be a meaningful thing for a lot of classes
On the other hand, although it would be a useful function for every object to make a clone of itself they decided not to let every class implement ICloneable.
Whether it is wise for you to have (almost every) objects of your application a common interface depends on what you will do with this interface and the advantage of all objects implementing such an interface versus the burden of being obliged to implement the interface.
For example, if the entities you are talking about are database records, then it is very likely that every class will have some kind of ID. You could consider giving every class an interface with one get property that returns the value of the ID of the record.
public interface IID
{
long ID {get;}
}
The advantage are multifold:
You encourage every designer of database classes to implement the same type of primary key (in this case a long), and the same property name
Advantage: it is easier to spot the ID of a record
Advantage: it is easier to change the type of the ID
Advantage: you know if you have a database record, you know some of the functions the record must have, without really knowing the type of the record.
Even if the designer needs a different type, or different name, he can still create a special function to implement the interface:
public class Person : IID
{
public int ID {get; set;}
IID:ID {get {return this.ID;} }
}
However, I suggest not to force interfaces to object for which it is not natural to have them. This has the advantage that you can't use these strange functions for object that have no real usage for them.
For example, most classes that represent some ordered numerical value have some notion of addition. Not only for integers and real numbers, but also for classes that represent a time span: 4 days and 23 hours + 1 day and 7 ours = 6 days and 6 hours. So for a time span addition is a useful interface
However, for a date, addition is not meaningful: 4th of july + 14 juillet = ?
So: Yes, implement interfaces for items that are natural to them. They force common naming and enable reuse. No, don't implement them for items that do not have a natural meaning for the functions.
Yes do it like this, it is the best practise. This gives you the advantage of polymorphism. You should do it in better way in current context is not good, because Student is not a Teacher. If you want to share common interface you should define it as: IUniversityMember. Here an example for your case which I think will make it clear.
public interface IUniversityMember
{
//... here common fields between `Teacher` and `Student`
string Name{ get; set;}
string Gender { get; set;}
}
//after that
public interface IStudent
{
int GetGPA();
int CreditsToPass {get; private set;}
}
public interface ITeacher
{
int WorkedHours {get; set;}
decimal PayPerHour {get; private set;}
}
public class BiologicalStudent: IUniversityMember, IStudent
{
public int CreditsToPast {get; private set;}
public BiologicalStudent ()
{
CreditsToPast = 5;
}
//stuff
public int GetGPA()
{
return 3;
}
}
public class MathStudent: IUniversityMember, IStudent
{
public int CreditsToPast {get; private set;}
public BiologicalStudent ()
{
CreditsToPast = 9;
}
public int GetGPA()
{
return 2;
}
}
public class BiologicalTeacher: IUniversityMember, ITeacher
{
public int WorkedHours { get; set;}
public decimal PayPerHour {get; private set;}
public MathTeacher()
{
PayPerHour = 8;
}
}
public class MathTeacher: IUniversityMember, ITeacher
{
public int WorkedHours { get; set;}
public decimal PayPerHour {get; private set;}
public MathTeacher()
{
PayPerHour = 10;
}
}
//Now if you have a university class
public class OxfordUniversity:IUniversity //can inherit interface too
{
public int MinGAPForSchollarship {get; private set;}
public OxfordUniversity()
{
MinGAPForSchollarship = 3;
}
public decimal PaySallary(ITeacher teacher)
{
return teacher.WorkedHours*teacher.PayPerHour;
}
public bool CheckForSchollarship(IStudent student)
{
int gpa = student.GetGPA();
//do some checks
if(gpa >= MinGAPForSchollarship)
return true;
return false;
}
}
I know the feature doesn't exist in C#, but PHP recently added a feature called Traits which I thought was a bit silly at first until I started thinking about it.
Say I have a base class called Client. Client has a single property called Name.
Now I'm developing a re-usable application that will be used by many different customers. All customers agree that a client should have a name, hence it being in the base-class.
Now Customer A comes along and says he also need to track the client's Weight. Customer B doesn't need the Weight, but he wants to track Height. Customer C wants to track both Weight and Height.
With traits, we could make the both the Weight and the Height features traits:
class ClientA extends Client use TClientWeight
class ClientB extends Client use TClientHeight
class ClientC extends Client use TClientWeight, TClientHeight
Now I can meet all my customers' needs without adding any extra fluff to the class. If my customer comes back later and says "Oh, I really like that feature, can I have it too?", I just update the class definition to include the extra trait.
How would you accomplish this in C#?
Interfaces don't work here because I want concrete definitions for the properties and any associated methods, and I don't want to re-implement them for each version of the class.
(By "customer", I mean a literal person who has employed me as a developer, whereas by "client" I'm referring a programming class; each of my customers has clients that they want to record information about)
You can get the syntax by using marker interfaces and extension methods.
Prerequisite: the interfaces need to define the contract which is later used by the extension method. Basically the interface defines the contract for being able to "implement" a trait; ideally the class where you add the interface should already have all members of the interface present so that no additional implementation is required.
public class Client {
public double Weight { get; }
public double Height { get; }
}
public interface TClientWeight {
double Weight { get; }
}
public interface TClientHeight {
double Height { get; }
}
public class ClientA: Client, TClientWeight { }
public class ClientB: Client, TClientHeight { }
public class ClientC: Client, TClientWeight, TClientHeight { }
public static class TClientWeightMethods {
public static bool IsHeavierThan(this TClientWeight client, double weight) {
return client.Weight > weight;
}
// add more methods as you see fit
}
public static class TClientHeightMethods {
public static bool IsTallerThan(this TClientHeight client, double height) {
return client.Height > height;
}
// add more methods as you see fit
}
Use like this:
var ca = new ClientA();
ca.IsHeavierThan(10); // OK
ca.IsTallerThan(10); // compiler error
Edit: The question was raised how additional data could be stored. This can also be addressed by doing some extra coding:
public interface IDynamicObject {
bool TryGetAttribute(string key, out object value);
void SetAttribute(string key, object value);
// void RemoveAttribute(string key)
}
public class DynamicObject: IDynamicObject {
private readonly Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.Ordinal);
bool IDynamicObject.TryGetAttribute(string key, out object value) {
return data.TryGet(key, out value);
}
void IDynamicObject.SetAttribute(string key, object value) {
data[key] = value;
}
}
And then, the trait methods can add and retrieve data if the "trait interface" inherits from IDynamicObject:
public class Client: DynamicObject { /* implementation see above */ }
public interface TClientWeight, IDynamicObject {
double Weight { get; }
}
public class ClientA: Client, TClientWeight { }
public static class TClientWeightMethods {
public static bool HasWeightChanged(this TClientWeight client) {
object oldWeight;
bool result = client.TryGetAttribute("oldWeight", out oldWeight) && client.Weight.Equals(oldWeight);
client.SetAttribute("oldWeight", client.Weight);
return result;
}
// add more methods as you see fit
}
Note: by implementing IDynamicMetaObjectProvider as well the object would even allow to expose the dynamic data through the DLR, making the access to the additional properties transparent when used with the dynamic keyword.
Traits can be implemented in C# 8 by using default interface methods. Java 8 introduced default interface methods for this reason too.
Using C# 8, you can write almost exactly what you proposed in the question. The traits are implemented by the IClientWeight, IClientHeight interfaces that provide a default implementation for their methods. In this case, they just return 0:
public interface IClientWeight
{
int getWeight()=>0;
}
public interface IClientHeight
{
int getHeight()=>0;
}
public class Client
{
public String Name {get;set;}
}
ClientA and ClientB have the traits but don't implement them. ClientC implements only IClientHeight and returns a different number, in this case 16 :
class ClientA : Client, IClientWeight{}
class ClientB : Client, IClientHeight{}
class ClientC : Client, IClientWeight, IClientHeight
{
public int getHeight()=>16;
}
When getHeight() is called in ClientB through the interface, the default implementation is called. getHeight() can only be called through the interface.
ClientC implements the IClientHeight interface so its own method is called. The method is available through the class itself.
public class C {
public void M() {
//Accessed through the interface
IClientHeight clientB = new ClientB();
clientB.getHeight();
//Accessed directly or through the class
var clientC = new ClientC();
clientC.getHeight();
}
}
This SharpLab.io example shows the code produced from this example
Many of the traits features described in the PHP overview on traits can be implemented easily with default interface methods. Traits (interfaces) can be combined. It's also possible to define abstract methods to force classes to implement certain requirements.
Let's say we want our traits to have sayHeight() and sayWeight() methods that return a string with the height or weight. They'd need some way to force exhibiting classes (term stolen from the PHP guide) to implement a method that returns the height and weight :
public interface IClientWeight
{
abstract int getWeight();
String sayWeight()=>getWeight().ToString();
}
public interface IClientHeight
{
abstract int getHeight();
String sayHeight()=>getHeight().ToString();
}
//Combines both traits
public interface IClientBoth:IClientHeight,IClientWeight{}
The clients now have to implement thet getHeight() or getWeight() method but don't need to know anything about the say methods.
This offers a cleaner way to decorate
SharpLab.io link for this sample.
C# language (at least to version 5) does not have support for Traits.
However, Scala has Traits and Scala runs on the JVM (and CLR). Therefore, it's not a matter of run-time, but simply that of the language.
Consider that Traits, at least at the Scala sense, can be thought of as "pretty magic to compile in proxy methods" (they do not affect the MRO, which is different from Mixins in Ruby). In C# the way to get this behavior would be to use interfaces and "lots of manual proxy methods" (e.g. composition).
This tedious process could be done with a hypothetical processor (perhaps automatic code generation for a partial class via templates?), but that's not C#.
Happy coding.
I'd like to point to NRoles, an experiment with roles in C#, where roles are similar to traits.
NRoles uses a post-compiler to rewrite the IL and inject the methods into a class. This allows you to write code like that:
public class RSwitchable : Role
{
private bool on = false;
public void TurnOn() { on = true; }
public void TurnOff() { on = false; }
public bool IsOn { get { return on; } }
public bool IsOff { get { return !on; } }
}
public class RTunable : Role
{
public int Channel { get; private set; }
public void Seek(int step) { Channel += step; }
}
public class Radio : Does<RSwitchable>, Does<RTunable> { }
where class Radio implements RSwitchable and RTunable. Behind the scenes, Does<R> is an interface with no members, so basically Radio compiles to an empty class. The post-compilation IL rewriting injects the methods of RSwitchable and RTunable into Radio, which can then be used as if it really derived from the two roles (from another assembly):
var radio = new Radio();
radio.TurnOn();
radio.Seek(42);
To use radio directly before rewriting happened (that is, in the same assembly as where the Radio type is declared), you have to resort to extensions methods As<R>():
radio.As<RSwitchable>().TurnOn();
radio.As<RTunable>().Seek(42);
since the compiler would not allow to call TurnOn or Seek directly on the Radio class.
There is an academic project, developed by Stefan Reichart from the Software Composition Group at the University of Bern (Switzerland), which provides a true implementation of traits to the C# language.
Have a look at the paper (PDF) on CSharpT for the full description of what he has done, based on the mono compiler.
Here is a sample of what can be written:
trait TCircle
{
public int Radius { get; set; }
public int Surface { get { ... } }
}
trait TColor { ... }
class MyCircle
{
uses { TCircle; TColor }
}
Building on what Lucero suggested, I came up with this:
internal class Program
{
private static void Main(string[] args)
{
var a = new ClientA("Adam", 68);
var b = new ClientB("Bob", 1.75);
var c = new ClientC("Cheryl", 54.4, 1.65);
Console.WriteLine("{0} is {1:0.0} lbs.", a.Name, a.WeightPounds());
Console.WriteLine("{0} is {1:0.0} inches tall.", b.Name, b.HeightInches());
Console.WriteLine("{0} is {1:0.0} lbs and {2:0.0} inches.", c.Name, c.WeightPounds(), c.HeightInches());
Console.ReadLine();
}
}
public class Client
{
public string Name { get; set; }
public Client(string name)
{
Name = name;
}
}
public interface IWeight
{
double Weight { get; set; }
}
public interface IHeight
{
double Height { get; set; }
}
public class ClientA : Client, IWeight
{
public double Weight { get; set; }
public ClientA(string name, double weight) : base(name)
{
Weight = weight;
}
}
public class ClientB : Client, IHeight
{
public double Height { get; set; }
public ClientB(string name, double height) : base(name)
{
Height = height;
}
}
public class ClientC : Client, IWeight, IHeight
{
public double Weight { get; set; }
public double Height { get; set; }
public ClientC(string name, double weight, double height) : base(name)
{
Weight = weight;
Height = height;
}
}
public static class ClientExt
{
public static double HeightInches(this IHeight client)
{
return client.Height * 39.3700787;
}
public static double WeightPounds(this IWeight client)
{
return client.Weight * 2.20462262;
}
}
Output:
Adam is 149.9 lbs.
Bob is 68.9 inches tall.
Cheryl is 119.9 lbs and 65.0 inches.
It isn't quite as nice as I'd like, but it's not too bad either.
This is really an suggested extension to Lucero's answer where all the storage was in the base class.
How about using dependency properties for this?
This would have the effect of making the client classes light weight at run time when you have many properties that are not always set by every descendant. This is because the values are stored in a static member.
using System.Windows;
public class Client : DependencyObject
{
public string Name { get; set; }
public Client(string name)
{
Name = name;
}
//add to descendant to use
//public double Weight
//{
// get { return (double)GetValue(WeightProperty); }
// set { SetValue(WeightProperty, value); }
//}
public static readonly DependencyProperty WeightProperty =
DependencyProperty.Register("Weight", typeof(double), typeof(Client), new PropertyMetadata());
//add to descendant to use
//public double Height
//{
// get { return (double)GetValue(HeightProperty); }
// set { SetValue(HeightProperty, value); }
//}
public static readonly DependencyProperty HeightProperty =
DependencyProperty.Register("Height", typeof(double), typeof(Client), new PropertyMetadata());
}
public interface IWeight
{
double Weight { get; set; }
}
public interface IHeight
{
double Height { get; set; }
}
public class ClientA : Client, IWeight
{
public double Weight
{
get { return (double)GetValue(WeightProperty); }
set { SetValue(WeightProperty, value); }
}
public ClientA(string name, double weight)
: base(name)
{
Weight = weight;
}
}
public class ClientB : Client, IHeight
{
public double Height
{
get { return (double)GetValue(HeightProperty); }
set { SetValue(HeightProperty, value); }
}
public ClientB(string name, double height)
: base(name)
{
Height = height;
}
}
public class ClientC : Client, IHeight, IWeight
{
public double Height
{
get { return (double)GetValue(HeightProperty); }
set { SetValue(HeightProperty, value); }
}
public double Weight
{
get { return (double)GetValue(WeightProperty); }
set { SetValue(WeightProperty, value); }
}
public ClientC(string name, double weight, double height)
: base(name)
{
Weight = weight;
Height = height;
}
}
public static class ClientExt
{
public static double HeightInches(this IHeight client)
{
return client.Height * 39.3700787;
}
public static double WeightPounds(this IWeight client)
{
return client.Weight * 2.20462262;
}
}
This sounds like PHP's version of Aspect Oriented Programming. There are tools to help like PostSharp or MS Unity in some cases. If you want to roll-your-own, code-injection using C# Attributes is one approach, or as suggested extension methods for limited cases.
Really depends how complicated you want to get. If you are trying to build something complex I'd be looking at some of these tools to help.
I'm trying to get my head around a polymorphism/inheritance situation in C#.
What I have right now is these classes:
Lease (the base class containing the general data)
PrivateLease (inheriting from the Lease class)
BusinessLease (inheriting from the Lease class)
What I want to achieve is this:
Lease lease = new PrivateLease();
This works at the moment, but I am not able to access the properties on the PrivateLease object when doing this. At least not without casting the Lease object to a PrivateLease object first.
I'd like the Lease object to be the general object of either a PrivateLease or BusinessLease object which holds all the data for one of the objects. Then when inserting/updating/deleting to the database I'm going to ask which type it is first to dertermine which tables to insert the data into.
I've got a strange feeling that the above is not the right approach to solve this problem. Does anyone have any hints on this? :-) I've searched on google and read in my programming books and everyone suggests this approach of having a base class and then inherit from it to the other classes.
Any help/hint is greatly appreciated!
Thanks in advance.
EDIT
Should've elaborated a bit on this from the beginning, I'm sorry for that!
The above mentioned classes are merely just holding data from the UI of my ASP.NET solution to perform CRUD operations against the database via a Data Access Layer. So bascially these classes only contains a bunch of properties to hold data. I.e:
public class Lease
{
public int Id { get; set; }
public bool IsActive { get; set; }
public string TypeOfRental { get; set; }
public string RentalPeriod { get; set; }
public DateTime TakeoverDate { get; set; }
}
public class PrivateLease : Lease
{
public string Floor { get; set; }
public string Side { get; set; }
public int FloorSize { get; set; }
public int NumberOfRooms { get; set; }
}
etc..
The PrivateLease and BusinessLease classes are different because of the different leaseing-variables that exists in the real world :-)
Basically I could just go with the two separate PrivateLease and BusinessLease objects, but since the model dictates that an Address object can hold one or more Leases, this is not an option.
To me it seems like I'm going to go through a major casting hell both on the ASP.NET frontend and on the DAL? :-/
Don't decide (choose a logic) on the layer of consumer, but let to decide by the classes themselves:
// or you ILease interface if a parent class will not contain any shared logic
abstract class Lease
{
public abstract void Do();
// example of shared logic
protected void Save(Lease l) { }
}
class PrivateLease : Lease
{
public override void Do() { // private logic here }
}
class BusinessLease : Lease
{
public override void Do() { // business logic here }
}
Usage:
Lease l = ...
l.Do(); // execute the logic
You may want to create a factory for objects creation:
static class LeaseFactory<T> where T : Lease, new() // constraint to require default constructor existence
{
public static Leas Create()
{
return new T();
}
}
You're right in the basic approach of having a base class.
What you need to do is to put any common properties in the base class. Then if you have different business rules, those can be implemented with virtual functions, being called polymorphically.
abstract class Lease
{
public int MonthlyCost {get;set;}
public string CustomerName {get;set;}
// Declare that all Leases have to have an IncreaseCost method.
public abstract void IncreaseCost();
}
class PrivateLease : Lease
{
// Private leases are incremented by an absolute number (10).
public override void IncreaseCost()
{
MonthlyCost += 10;
}
}
class BusinessLease : Lease
{
// Business leases are incremented by 10%.
public override void IncreaseCost()
{
MonthlyCost *= 1.10;
}
}
// Somewhere in your code...
Lease lease = new PrivateLease();
// This call is polymorphic. It will use the actual type of the lease object.
lease.IncreaseCost();
In the modern OOD you can use interfaces, for this situation.
Edit:
In my opinion, to avoid casting, you can have multiple interfaces for multiple purposes. then PrivateLease and BusinessLease can implement the appropriate ones.
interface IWrite
{
string Data { get; set; }
void Write();
}
interface IRead
{
string Data { get; set; }
void Read();
}
public class Lease
{
//..
}
public class PrivateLease : Lease, IWrite, IRead
{
// other implementations
public string Data { get; set; }
public void Read()
{
//..
}
public void Write()
{
//..
}
}
public class BusinessLease : Lease, IRead
{
// other implementations
public string Data { get; set; }
public void Read()
{
//..
}
}
In Lease class add virtual method called DBUpdate and override it in both the derived classes.
Let's say some Utility class has LeaseDBOperation Method looks like this :
public static void LeaseDBOperation (Lease anylease)
{
anyleaase.DBUpdate();
}
you can call this method as :
var pl = new PrivateLease();
..set all the properties of **pl**
//call this for db operations :
Utility.LeaseDBOperation(pl)
Here in LeaseDBOperation method , if based on the type send , DBUpdate method of required class will be called.
Lease l = (Lease)sth;
if (l is PrivateLease)
{
PrivateLease p = (PrivateLease)l;
//do private logic here
}
else if (l if BussinessLease)
{
BussinessLease b = (BunessinessLease)l;
//do bussiness logic here
}
I have a class Voucher:
public abstract class Voucher
{
public int Id { get; set; }
public decimal Value { get; protected set; }
public const string SuccessMessage = "Applied";
}
and a subclass GiftVoucher
public class GiftVoucher : Voucher
{
}
and another subclass DiscountVoucher
public class DiscountVoucher : Voucher
{
public decimal Threshold { get; private set; }
public string FailureMessage { get { return "Please spend £{0} to use this discount"; } }
}
You can see that DiscountVoucher has a couple of specific properties Threshold and FailureMessage that respectively represent the amount of money you need to spend to get the discount and the failure message to display if the user has not spent that money.
My question is this. I have a collection of Voucher objects and what I don't want to do in my code is something like this
if (voucher is DiscountVoucher)
{
// cast voucher to a DiscountVoucher and then call the specific methods on it
}
because this is not at all maintainable. At the same time I did not want to put those specific methods in the Voucher abstract class because they are not applicable to all types of Vouchers. Does anyone know how to design this functionality?
In the general case: No!
Handling specialized scenarios in a general code flow without any code handling the special cases does not work.
However in some cases you can cheat a little bit. You can implement virtual methods in the abstract base class that provides a default "nothing" implementation.
Could be a method that returns null, 0 or just does nothing.
In this case
public virtual string FailureMessage { get { return string.Empty; } }
might be a reasonable implementation.
I guess that your implementation looks a lot like the template method pattern. Then it is perfectly normal to have void implementations for steps not applicable to certain implementations.
Well what you've got here is a version of the strategy pattern. I don't think there's any getting away from eventually having to decide if you have one type of voucher or another but you can limit the number of variations - voucher categories if you will - using interfaces.
For instance you might end up with five vouchers which implement interfaces called 'StandardVoucher' and three called 'DiscountVoucher' but instead of having to handle eight cases you now just have two.
The interfaces can cover a range of vouchers showing the available methods without worrying about the details of each vouchers implementation.
No, you cannot, because iterating over more general objects and then calling specific methods would require using polymorphism to have dedicated functionality in each subclass. Without a method in the superclass to override, you have no way to obtain what you want.
I think you're right to be suspicious of the code you describe.
My first thought is that if members of DiscountVoucher aren't broad enough to exist as virtual or abstract in Voucher, then a function that takes a Voucher as a parameter should not touch them.
So, to solve the problem, I'd say you could do one of two things:
First, you could add virtual methods or properties to Voucher, e.g.
public abstract class Voucher
{
public int Id { get; set; }
public decimal Value { get; protected set; }
public const string SuccessMessage = "Applied";
public decimal Threshold { get { return 0.0; } }
public string FailureMessage { get { return ""; } }
}
Second, you can add methods that do what you expect for each Voucher. You've grouped them together as vouchers, so think about what they have in common. If, say, GiftVoucher and DiscountVoucher are both doing their own calculations to determine if they apply to the current ShoppingCart, then you could have a Voucher method called isValid() to detect this. For example,
public abstract class Voucher
{
public bool isValid(ShoppingCart sc);
public string FailureMessage { get { return "This voucher does not apply"; } }
// ...
}
public class DiscountVoucher : Voucher
{
private decimal Threshold;
public override bool isValid(ShoppingCart sc)
{
return (sc.total >= Threshold);
}
public override string FailureMessage
{
get { return FormatString("Please spend £{0} to use this discount", Threshold); }
}
There are just cases where you will have to cast. Here I would implement a general error checking mechanism:
public abstract class Voucher
{
public int Id { get; set; }
public decimal Value { get; protected set; }
public virtual string SuccessMessage { get { return "Applied"; } }
public virtual string FailureMessage { get { return String.Empty; } }
public virtual bool Ok { get { return true; } }
}
public class GiftVoucher : Voucher { }
public class DiscountVoucher : Voucher
{
public decimal Threshold { get; private set; }
public override string FailureMessage { get { return "Please spend £{0} to use this discount"; } }
public override bool Ok { get { return Value >= Threshold; } }
}
You can then test the integrity of a voucher of any type without casting:
if (voucher.Ok) {
Console.WriteLine(voucher.SuccessMessage);
} else {
Console.WriteLine(voucher.FailureMessage);
}
As a general rule, try to let objects do their own stuff (here to test if they are OK) instead of doing it from the "outside". Even the fact, that no error can occur in a GiftVoucher needs not to be known by the "outer world".
This is probably my naivety showing through, but anyway...
I have a generic interface which defines a set of standard methods (implemented differently) across implementations.
I pass the interface into a method as a parameter, this method being responsible for persisting to a database. E.g. I have some implementations called bug, incident, etc, defined from the generic interface (called IEntry). These concerete implementations also make use of IEnumerable
Because a bug is different to an incident, there are different fields. When I pass the interface into a method as a parameter, is there any way to inference the type? So if I pass in the Bug object, I can use its fields, which are not the same fields as in those of Incident. These fields are useful for the persistance to the database. I'm assuming no because there is no way to know what the type to be passed in will be (obviously), but I know people here have more wisdom. In that case, is there a better way of doing things? Because of the similarity, I would like to stick to interfaces.
EDIT: I guess the other way is to make use of some flow control to generate the sql statement on the fly and then pass it in as a parameter.
Thanks
The thing about passing objects and interfaces around is that you really shouldn't be concerned with the actual type, as long as it inherits from/implements the particular base class/interface you're interested in.
So building logic into that method to figure out that it's a bug, and then accessing things that are only present for bugs, that's basically not the OOP way, although it might be the "best" way in your particular case.
I would, however, advise against it, and instead try to build a proper OOP way with polymorphism to handle the differences, instead of building it into the method as special cases.
You mention persistence, is this method responsible for storing the data somewhere? Perhaps you could separate the part that gathers the information to store from the part that stores the information, that way you could ask the object itself to provide you with all the pertinent information, which could vary from one class to another.
Bad Design (as I think was described in the question):
public interface IEntry
{
string Description { get; set; }
}
public class Bug : IEntry
{
public int ID { get; set; }
public string Description { get; set; }
public string UserName { get; set; }
}
public class Incident : IEntry
{
public Guid ID { get; set; }
public string Description { get; set; }
}
public class Persister
{
public void Save(IEnumerable<IEntry> values)
{
foreach (IEntry value in values) { Save(value); }
}
public void Save(IEntry value)
{
if (value is Bug) { /* Bug save logic */ }
else if (value is Incident) { /* Incident save logic */ }
}
}
Improved design (smart entity approach):
public interface IEntry
{
string Description { get; set; }
void Save(IPersister gateway);
}
public class Bug : IEntry
{
public int ID { get; set; }
public string Description { get; set; }
public string UserName { get; set; }
public void Save(IPersister gateway)
{
gateway.SaveBug(this);
}
}
public class Incident : IEntry
{
public Guid ID { get; set; }
public string Description { get; set; }
public void Save(IPersister gateway)
{
gateway.SaveIncident(this);
}
}
public interface IPersister
{
void SaveBug(Bug value);
void SaveIncident(Incident value);
}
public class Persister : IPersister
{
public void Save(IEnumerable<IEntry> values)
{
foreach (IEntry value in values) { Save(value); }
}
public void Save(IEntry value)
{
value.Save(this);
}
public void SaveBug(Bug value)
{
// Bug save logic
}
public void SaveIncident(Incident value)
{
// Incident save logic
}
}
The improved design is only caters for the need to shift the need for change of Persister.Save(IEntry). I just wanted to demonstrate a first step to make the code less brittle. In reality and production code you would want to have a BugPersister and IncidentPersister class in order to conform to the Single Responsibility principle.
Hope this more code-centric example is a help.
The persistance thing is just a method in a class to upload details to a database.
I guess I could write an abstract class with a function for the persistance requirement and that could be based on parameters for it to work. I can use this in each of my interface implementations. Because the way the update to db will happen (pretty much the same but a few words in a sql query change), I can generate this based on method parameters.