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".
Related
I am trying to refactor below code to adhere open close principle
Its some bit of code extracted for question purpose but basically here calculate method behave differently based on invoice type
public class Invoice
{
private string _type;
public double Calculate(double amount)
{
if(_type == "invoice")
{
return amount + 10;
}
else
{
return amount - 10;
}
}
}
I have done it up to here
public interface IInvoice
{
double Calculate(double amount);
}
public class Invoice : IInvoice
{
public double Calculate(double amount)
{
return amount + 10;
}
}
public class DiscountInvoice : IInvoice
{
public double Calculate(double amount)
{
return amount - 10;
}
}
I get below model from a API endpoint, where "Type" determine weather to use Invoice or DiscountInvoice. I like to avoid putting if condition on type field
public class InvoiceModel
{
public int Id { get; set; }
public string Type { get; set; }
public double Amount { get; set; }
}
static void Main(string[] args)
{
private IInvoice _invoice;
//I am not sure how to detect and use the correct invoice type here. without doing below
//based on something i have to assign
_invoice = new Invoice() or new DiscountInvoice()
}
First of all your structure looks good and meets the open-closed principle.
In terms of determination which implementation of the abstraction to use, you need to consider the business logic, as the decision directly depends on that. If you have several implementations of IInvoice, then I assume you need all of them at some point in your application. So based on your business logic you have to decide which one to use.
You can consider Factory pattern, that will take care of that and return you the right type. All the business logic will be encapsulated there. Just when implementing your factory, also keep in mind the LSP (Liskov Substitution Principle), as it's quite easy to break it.
I have been battling with this bit of code for a while now and I am trying to get a solution as it is literally the last part before it goes to testing.
I have the following interfaces and classes (simplified to the relevant parts):
public interface ITagParent<T> where T : ITag
{
List<TagAddOn<T>> TagCollection { get; set; }
}
public interface ITag
{
int Id { get; set; }
string Description { get; set; }
TagGroup TagGroup { get; set; }
}
public class TagAddOn<T> : ViewModelBase where T : ITag
{
private T _currentTag;
public T CurrentTag
{
get { return _currentTag; }
set { _currentTag = value; }
}
}
public partial class Customer : ITagParent<CustomerTag>
{
List<TagAddOn<CustomerTag>> _tagCollection;
public List<TagAddOn<CustomerTag>> TagCollection
{
get { return _tagCollection; }
set { _tagCollection = value; }
}
}
public partial class CustomerTag : ITag
{
public int Id { get; set; }
}
public class TagAddOnManager
{
public static string GetTagCurrentValue(List<TagAddOn<ITag>> dataObjectAddOns)
{
// LOTS OF SNIPPING!
return string.Empty;
}
}
I am trying to use the GetTagCurrentValue method in the TagAddOnManager class like this:
string value = TagAddOnManager.GetTagCurrentValue(
((ITagParent<ITag>)gridCell.Row.Data).TagCollection));
Everything compiles fine, but errors when trying to cast gridCell.Row.Data to ITagParent<ITag>. I understand this is due to covarience and a workaround (if not a terribly safe one) is to mark T in the ITagParent interface with the out keyword, but that won't work as you can see it is used in the TagCollection property, which can't be read only.
I tried casting the above to ITagParent<CustomerTag>, but this fails at compile time with a 'cannot convert' error when trying to feed it into my GetTagCurrentValue method.
Another option I considered is using some base classes instead of the ITagParent interface, but that won't work as the Customer object already inherits from another base class, which can't be modified for this implementation.
I know I could just overload the GetTagCurrentValue method with List<TagAddOn<CustomerTag>> as the parameter type and all other variations, but that really seems like a 'I give up' solution. I could probably use reflection to get the desired results, but that would be unwieldy and not very efficient, especially considering this method could be called a lot in a particular process.
So does anyone have any suggestions?
Could you use something like that
public class TagAddOnManager
{
public static string GetTagCurrentValue<TTag>(ITagParent<TTag> tagParent)
where TTag : ITag
{
// Just an example.
return tagParent.TagCollection.First().CurrentTag.Description;
}
}
and use it like that?`
var value = TagAddOnManager.GetTagCurrentValue((Customer)CustomergridCell.Row.Data);
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 scenario where I have a bunch of jobs that I am scheduling to run at various times, the jobs themselves are being handled generically already which is great. And I have an abstract BaseJob class that they all inherit from that I use for common things (like the jobPK, startTime, exception logging, reporting, etc). But beyond that the jobs are very different, they have different properties and data associated with them that is entriely specific to them (I call these proprties JobDetails). So for example:
JobDetails for Job1
-customerId int
-cost double
-sku string
-userDefinedProperties SomeCustomObjectType
JobDetails for Job2
-name string
-executionDate DateTime
-otherProperties SomeOtherCustomObjectType
In the base class I would like to be able to store a reference to these JobDetails in as generic a fashion as possible (so in other words I don't want to just store it as object) to minimize the overhead for boxing/unboxing. Then I want to have the BaseJob class handle a lot of the common functionality that is needed for the app, so for example, if a job fails, I want to save its JobDetails to the database so that it can be restarted, I also want to log any errors that may have occured to a given job. For this I need to be able to extract those JobDetails and make use of them.
It seems like I need to make use of .NET generics and have a class of generic properties that I can stuff anything into and not have to worry about typing. What's the best way to handle this and make it efficient and flexible?
I hope that is clear, thanks for the help
You can make the JobDetails implement an interface and let have BaseJob have an abstract reference to it. Then in the actual jobs you implement the abstract JobDetails with the implementation you want. Then let the JobDetails interface define the methods BaseJob needs to work with. This is a slight variation on the Template Method design pattern. It would look something like this:
public interface IJobDetails {
void DoSomeWork();
}
public abstract BaseJob {
protected abstract IJobDetails JobDetails { get; set; }
public ExecuteJob {
//execute the job
JobDetails.DoSomeWork();
}
}
public Job1 : BaseJob {
public Job1() {
JobDetails = new ConcreteJobDetails();
}
protected override IJobDetails JobDetails { get; set; }
}
How about something like...
public abstract class JobBase<TDetails>
{
private TDetails details;
protected TDetails Details
{
get
{
if (details == null)
{
this.details = this.LoadDetails();
}
return this.details;
}
}
protected virtual TDetails LoadDetails()
{
// Some kind of deserialization of TDetails from your DB storage.
}
}
public class ExampleJob : JobBase<ExampleJob.ExampleJobDetails>
{
public class ExampleJobDetails
{
public string ExampleProperty { get; set; }
public int AnotherProperty { get; set; }
}
}
You'd either want to have tables for each type used as TDetails or one big Key/Value based table for all of them. There are pros/cons to both. If you are super paranoid about boxing, there's no reason why TDetails can't be constrained to be a struct, too.
Edit: Got it backwards, you want to save the details on a failure. How about...
public abstract class JobBase<TDetails>
{
protected TDetails Details { get; private set; }
public JobBase()
{
this.Details = this.CreateDetails();
}
protected abstract TDetails CreateDetails();
protected void SaveDetails()
{
// Generic save to database.
}
}
public class ExampleJob : JobBase<ExampleJob.ExampleJobDetails>
{
public class ExampleJobDetails
{
public string ExampleProperty { get; set; }
public int AnotherProperty { get; set; }
}
protected override ExampleJobDetails CreateDetails()
{
return new ExampleJobDetails() { ExampleProperty = "Hi.", AnotherProperty = 1 };
}
}
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.