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
}
Related
I have two groups of classes in my code and one group has logic and other group has data and inheritance is also being used in each group. I tried to mimic the situation which I am dealing with in below code snippet. The problem I have is how to handle the objects of derived data classes efficiently in related instances of logic classes. Right now I am trying to cast the instance of derived data class in a method of derived logic class which I do not think is logical. I need some guidance to address this issue.
void Main()
{
var item1 = new D1();
var holder1 = new DataHolder1() { localProp1 = "test" };
var holderout = item1.Method1(holder1);
holderout.Dump();
}
public class BaseDataHolder
{
public string prop { get; set; }
}
public class DataHolder1 : BaseDataHolder
{
public string localProp1 { get; set; }
}
public class DataHolder2 : BaseDataHolder
{
public string localProp2 { get; set; }
}
public class BaseClass
{
public virtual BaseDataHolder Method1(BaseDataHolder holder)
{
return null;
}
}
public class D1 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder1).localProp1.Dump();
(holder as DataHolder1).localProp1 = "change1";
return holder;
}
}
public class D2 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder2).localProp2.Dump();
(holder as DataHolder2).localProp2 = "change2";
return holder;
}
}
I don't see why it would be illogical since looks like you are trying to get DataHolder1 always in class D1. Rather, why can't your class compose with Data class instance and use that in method like
public class D1 : BaseClass
{
private readonly DataHolder1 holder;
public D1(DataHolder1 holder) { this.holder = holder; }
public override BaseDataHolder Method1()
{
holder.localProp1.Dump();
holder.localProp1 = "change1";
return holder;
}
}
Then you can just say
var item1 = new D1(new DataHolder1());
BaseDataHolder data = item1.Method1();
This violates the Liskov substitution principle. In summary, it's bad, because your signature promises to work well with any BaseDataHolder but in reality it will just crash if the wrong BaseDataHolder is passed in.
I cannot really give a solution because we don't know your requirements. From what you have posted, your three logic classes should drop the inheritance and just have three different method signatures, each telling what it needs instead of all of them lying about what they need and then crashing randomly.
This question already has answers here:
Using Interface variables
(12 answers)
Closed 5 years ago.
I have fair understanding of interface/abstract class/class however just trying to understand something else. Look at below code:
namespace AbstractClassExample
{
class Program
{
static void Main(string[] args)
{
BaseEmployee fullTimeEmployee = new FullTimeEmployee();
BaseEmployee contractEmployee = new ContractEmployee();
}
}
public abstract class BaseEmployee
{
public string EmployeeID { get; set; }
public string EmployeeName { get; set; }
public string EmployeeAddress { get; set; }
public abstract double CalculateSalary(int hoursWorked);
}
public class FullTimeEmployee : BaseEmployee
{
public override double CalculateSalary(int hoursWorked)
{
//do something
}
}
public class ContractEmployee : BaseEmployee
{
public override double CalculateSalary(int hoursWorked)
{
//do something
}
}
}
however I fail to get below lines (1st approach):
BaseEmployee fullTimeEmployee = new FullTimeEmployee();
BaseEmployee contractEmployee = new ContractEmployee();
Why not written this way instead (2nd approach):
FullTimeEmployee fullTimeEmployee = new FullTimeEmployee();
it is completely okay to use 2nd approach it will work coz of relation. How would any developer in the work know if above abstract class is in DLL. Probably, will use 1st approach when you've code with you or sort of documentation. Isn't it?
Similar example would also be valid for interface declaration. like:
interface IPointy {
void MyMethod();
}
class Pencil : IPointy {
void MyMethod() {
}
void MyOtherMethod() {
}
}
IPointy itPt = new Pencil();
Isn't 1st approach making it complex? What's good practice? Any good practice vs bad practice with 1st & 2nd?
Using the first approach enables Polymorphism.
Let's say you have a company class:
class Company {
}
Of course, companies have full-time and contract employees. Let's add them as properties:
public FullTimeEmployee[] EmployeesFullTime { get; set; }
public ContractEmployees[] EmployeesContract { get; set; }
This seems all good.
But, what if your company can now have yet another kind of employee that has a different way of calculating his salary? You have to add another property:
public FullTimeEmployee[] EmployeesFullTime { get; set; }
public ContractEmployee[] EmployeesContract { get; set; }
public AnotherKindOfEmployee[] EmployeesOther { get; set; }
That's no good, is it? Every time you add a new kind of employee, you have to add another property!
That's why you use BaseEmployee, it does not care about what kind of employee it holds, and it can still calculate salary!
public BaseEmployee[] AllEmployees { get; set; }
One of the reasons that you'd assign a FullTimeEmployee to a BaseEmployee is that you can put them together into a collection of FullTimeEmployees' andContractEmployees`:
List<BaseEmployee> allEmployees = new List<BaseEmployee>()
{
new FullTimeEmployee() {...},
new FullTimeEmployee() {...},
new ContractEmployee() {...},
new FullTimeEmployee() {...},
}
This has the disadvantage that you can't use (efficiently) functionality of a FullTimeEmployee that ContractEmployees don't have, but if you don't need this functionality while processing allEmployees, this method is preferable above creating two collections of employees. For instance, you could write one function that would work for both FullTimeEmployees and ContractEmployees:
private void PaySalary(List<BaseEmployee> employees)
{
foreach (var employee in employees)
{
var salary = employee.CalculateSalary()
Pay(salary, ...);
}
}
One of the guidelines when creating an object oriented design is that you should design for change, meaning that your design should be such that you could easily add types to your design, or change internals of your classes.
Suppose you'll need a new type of employees, HiredEmployees. Because you derived them from BaseEmployee, you'll know you can calculate their salary. You don't have to change function PaySalary.
This would also have worked if you'd given your FullTimeEmployee and your ContractEmployee an interface:
interface ISalaryReceiver
{
double CalculateSalary(int hoursWorked);
}
class BaseEmployee
{
public string EmployeeID { get; set; }
...
}
class FullTimeEmployee : BaseEmployee, ISalaryReceiver
{
public override double CalculateSalary(int hoursWorked)
{
...
}
}
class ContractEmployee : BaseEmployee, ISalaryReceiver
{
public double CalculateSalary(int hoursWorked)
{
...
}
}
void PaySalary(List<ISalaryReceiver> employees)
{
...
}
This method would work. It is even ready for change: you can invent any employee as long as it implements ISalaryReceiver.
However!
Suppose your BaseEmploye has a function where it needs to CalculateSalary:
class BaseEmployee
{
...
public void PaySalary()
{
double salary = ... // how to calculate the salary?
}
}
You can't let BaseEmployee implement ISalaryReceiver, because a BaseEmployee doesn't know how to calculate the salary.
When using the abstract method, you can tell BaseEmployee, that every object of BaseEmployee knows how to CalculateSalary:
abstract class BaseEmployee
{
abstract double CalculateSalary(...);
public void PaySalary()
{
double salary = this.CalculateSalary(...);
...
}
}
So if your base class needs functions that are different per derived class, and there is no proper default functionality, then your base class needs an abstract function. It is guaranteed that every derived class has implemented this function, and thus the base class can call it.
Because in such cases it is not meaningful to create objects of the base class (after all, the base class doesn't know how to CalculateSalary), the base class has to be declared abstract with the result that you can't create objects of base class. Only object of derived classes that implement CalculateSalary can be created.
One of the benefits of abstract classes is - you can use abstract type for argument type in the method.
Suppose you have a Report class with method Generate which during report generation need to calculate employee salary
public class Report
{
public SalaryReport Generate(BaseEmployee employee)
{
// ...
var salary = employee.CalculateSalary();
// ...
}
}
You don't want use if..else statement in every method where you need calculate salary.
So in Report class doesn't care how CalculateSalary implemented, it only cares that Employee class have this method.
We all write code with some patterns even when we dont realise it. I am trying to really understand some of the S.O.L.I.D principles and how you apply these principles in the real world.
I am struggling with "D".
I sometimes confuse Dependency Inversion with Dependency Injection. Does it mean that as long as you keep things depending on abstraction (IE:interfaces) you are done.
Does anybody have even a small C# example that explains it?
Thanks.
Have a look at Mark Seeman's blog or, even better, buy his book. It covers so much more than just DI. I appreciate you probably just want a simple sample to get going with. However, it's a subject that many who claim to understand don't and therefore worth learning well.
That said, here's a very simple example. The terminology, as I understand it, is
Inversion of Control and Dependency Injection. Inversion of Control refers to the fact that you give control of a class's dependencies to some other class, opposed to the class controlling the dependency itself, usually via the new keyword. This control is exerted via Dependency Injection where a class is given, or injected, with its dependencies. This can be done via an IoC framework or in code (known as Pure DI). Injection can be performed in the class's constructor, via a property or as a method's parameter. Dependencies can be any type, they don't have to be abstract.
Here's a class that lists Tour de France winners who haven't doped:
class CleanRiders
{
List<Rider> GetCleanRiders()
{
var riderRepository = new MsSqlRiderRepository();
return riderRepository.GetRiders.Where(x => x.Doping == false);
}
}
This class is dependent on the MsSqlRiderRepository. The class takes control of the creation of the instance. The problem is that this dependency is inflexible. It's hard to change it to a OracleRiderRepository or a TestRiderRepository.
IoC and DI solve this for us:
class CleanRiders
{
private IRiderRepository _repository;
public CleanRiders(IRiderRepository repository)
{
_repository = repository;
}
List<Rider> GetCleanRiders()
{
return _repository.GetRiders.Where(x => x.Doping == false);
}
}
Now the class is only depending on an Interface. Control of the dependency has been given up to the class's creator and must be injected via its constructor:
void Main()
{
var c = new CleanRiders(new MsSqlRepository());
var riders = c.GetRiders();
}
Arguably, a more flexible, testable and SOLID approach.
S: Single Responsibility Principle
The following code has a problem. “Automobile” class contains two different responsibilities: First is to take care of the car model, adding accessories, etc. and then there is the second responsibility: To sell/lease the car. This breaks SRP. These two responsibilities are separate.
public Interface ICarModels {
}
public class Automobile : ICarModels {
string Color { get; set; }
string Model { get; set; }
string Year { get; set; }
public void AddAccessory(string accessory)
{
// Code to Add Accessory
}
public void SellCar()
{
// Add code to sell car
}
public void LeaseCar()
{
// Add code to lease car
}
}
To fix this issue, we need to break up the Automobile class and use separate interfaces:
public Interface ICarModels {
}
public class Automobile : ICarModels {
string Color { get; set; }
string Model { get; set; }
string Year { get; set; }
public void AddAccessory(string accessory)
{
// Code to Add Accessory
}
}
public Interface ICarSales {
}
public class CarSales : ICarSales {
public void SellCar()
{
// Add code to sell car
}
public void LeaseCar()
{
// Add code to lease car
}
}
While designing your interfaces and classes think about responsibilities. What will modifications to class involve? Break classes up into their simplest forms...but not any simpler (as Einstein would say).
O: Open/Closed Principle
When requirements change and more types are added for processing, classes should be extensible enough so that they don't require modifications. New classes can be created and used for processing. In other words classes should be extensible. I call this the "If-Type" principle. If you have lots of if (type == ....) in your code, you need to break it up into separate class levels.
In this example we are trying to calculate the total price of car models in a dealership.
public class Mercedes {
public double Cost { get; set; }
}
public class CostEstimation {
public double Cost(Mercedes[] cars) {
double cost = 0;
foreach (var car in cars) {
cost += car.Cost; } return cost; }
}
But a dealership does not only carry Mercedes! this is where the class is not extensible anymore! What if we want to add up other car model costs as well?!
public class CostEstimation {
public double Cost(object[] cars)
{
double cost = 0;
foreach (var car in cars)
{
if (car is Mercedes)
{
Mercedes mercedes = (Mercedes) car;
cost += mercedes.cost;
}
else if (car is Volkswagen)
{
Volkswagen volks = (Volkswagen)car;
cost += volks.cost;
}
}
return cost;
}
}
It's now broken! for every car model in the dealership lot we must Modify the class and add another if statement!
So let's fix it:
public abstract class Car
{
public abstract double Cost();
}
public class Mercedes : Car
{
public double Cost { get; set; }
public override double Cost()
{
return Cost * 1.2;
}
}
public class BMW : Car
{
public double Cost { get; set; }
public override double Cost()
{
return Cost * 1.4;
}
}
public class Volkswagen : Car
{
public double Cost { get; set; }
public override double Cost()
{
return Cost * 1.8;
}
}
public class CostEstimation {
public double Cost(Car[] cars)
{
double cost = 0;
foreach (var car in cars)
{
cost += car.Cost();
}
return cost;
}
}
Here the problem is solved!
L: Liskov Substitution Principle
The L in SOLID refers to Liskov principle. The inheritance concept of Object Oriented programming can be solidified where derived classes cannot modify behavior of base classes in any manner. I will come back to a real world example of LISKOV Principle. But for now this is the principle itself:
T -> Base
where as T [the derived class] should not be tampering with behavior of Base.
I: Interface Segragation Principle
Interfaces in c# lay out methods that will need to be implemented by classes that implement the interface. For example:
Interface IAutomobile {
public void SellCar();
public void BuyCar();
public void LeaseCar();
public void DriveCar();
public void StopCar();
}
Within this interface there are two groups of activities going on. One group belongs to a salesman and another belongs to a driver:
public class Salesman : IAutomobile {
// Group 1: Sales activities that belong to a salesman
public void SellCar() { /* Code to Sell car */ }
public void BuyCar(); { /* Code to Buy car */ }
public void LeaseCar(); { /* Code to lease car */ }
// Group 2: Driving activities that belong to a driver
public void DriveCar() { /* no action needed for a salesman */ }
public void StopCar(); { /* no action needed for a salesman */ }
}
In the above class we are forced to implement DriveCar and StopCar methods. Things that don't make sense for a salesman and do not belong there.
public class Driver : IAutomobile {
// Group 1: Sales activities that belong to a salesman
public void SellCar() { /* no action needed for a driver */ }
public void BuyCar(); { /* no action needed for a driver */ }
public void LeaseCar(); { /* no action needed for a driver */ }
// Group 2: Driving activities that belong to a driver
public void DriveCar() { /* actions to drive car */ }
public void StopCar(); { /* actions to stop car */ }
}
The same way we are now forced to implement SellCar, BuyCar and LeaseCar. Activities that clearly do not belong in Driver class.
To fix this issue we need to break up the interface into two pieces:
Interface ISales {
public void SellCar();
public void BuyCar();
public void LeaseCar();
}
Interface IDrive {
public void DriveCar();
public void StopCar();
}
public class Salesman : ISales {
public void SellCar() { /* Code to Sell car */ }
public void BuyCar(); { /* Code to Buy car */ }
public void LeaseCar(); { /* Code to lease car */ }
}
public class Driver : IDrive {
public void DriveCar() { /* actions to drive car */ }
public void StopCar(); { /* actions to stop car */ }
}
Segregation of Interfaces!
D : Dependency Inversion Principle
The question is: Who depends on who?
Let's say we have a traditional multi-layer application:
Controller Layer -> Business Layer -> Data Layer.
Assume from the Controller we want to tell the Business to save an Employee into the database. The Business Layer asks the Data Layer to perform this.
So we set out to create our Controller (MVC example):
public class HomeController : Controller {
public void SaveEmployee()
{
Employee empl = new Employee();
empl.FirstName = "John";
empl.LastName = "Doe";
empl.EmployeeId = 247854;
Business myBus = new Business();
myBus.SaveEmployee(empl);
}
}
public class Employee {
string FirstName { get; set; }
string LastName { get; set; }
int EmployeeId { get; set; }
}
Then in our Business Layer we have:
public class Business {
public void SaveEmployee(Employee empl)
{
Data myData = new Data();
myData.SaveEmployee(empl);
}
}
and in our Data Layer we create the connection and save the employee into the database. This is our traditional 3-Layer architecture.
Let's now make an improvement to our Controller. Instead of having SaveEmployee method right inside our controller, we can create a class that takes care of all Employee actions:
public class PersistPeople {
Employee empl;
// Constructor
PersistPeople(Employee employee) {
empl = employee;
}
public void SaveEmployee() {
Business myBus = new Business();
myBus.SaveEmployee();
}
public Employee RetrieveEmployee() {
}
public void RemoveEmployee() {
}
}
// Now our HomeController is a bit more organized.
public class HomeController : Controller {
Employee empl = new Employee();
empl.FirstName = "John";
empl.LastName = "Doe";
empl.EmployeeId = 247854;
PersistPeople persist = new Persist(empl);
persist.SaveEmployee();
}
}
Now let's concentrate on the PersistPeople class. It is hard-coded with and tightly coupled with the Employee class. It takes in an Emloyee in the contstructor and instantiates a Business class to save it. What if we want to save an "Admin" instead of "Employee"? Right now our Persist class is totally "Dependent" on the Employee class.
Let's use "Dependency Inversion" to solve this problem. But before doing that we need to create an interface that both Employee and Admin classes derive from:
Interface IPerson {
string FirstName { get; set; }
string LastName { get; set; }
int EmployeeId { get; set; }
}
public class Employee : IPerson {
int EmployeeId;
}
public class Admin : IPerson {
int AdminId;
}
public class PersistPeople {
IPerson person;
// Constructor
PersistPeople(IPerson person) {
this.person = person;
}
public void SavePerson() {
person.Save();
}
}
// Now our HomeController is using dependency inversion:
public class HomeController : Controller {
// If we want to save an employee we can use Persist class:
Employee empl = new Employee();
empl.FirstName = "John";
empl.LastName = "Doe";
empl.EmployeeId = 247854;
PersistPeople persist = new Persist(empl);
persist.SavePerson();
// Or if we want to save an admin we can use Persist class:
Admin admin = new Admin();
admin.FirstName = "David";
admin.LastName = "Borax";
admin.EmployeeId = 999888;
PersistPeople persist = new Persist(admin);
persist.SavePerson();
}
}
So in summary our Persist class is not dependent and hard-coded to Employee class. It can take any number of types like Employee, Admin, etc. The control to save whatever is passed in now lies with the Persist class and not the HomeController. The Persist class now knows how to save whatever is passed in (Employee, Admin, etc.). Control is now inverted and given to Persist class. You can also refer to this blog for some great examples of SOLID principles:
Reference: https://darkwareblog.wordpress.com/2017/10/17/
I hope this helps!
I was trying to explain this to my co-worker the other day and in the process I actually even understood the concept myself. Especially when I came up with the real-life example of dependency inversion in real life.
The story
Imagine if a car driver was dependent on a car: can only drive 1 car - THE car! This would be pretty bad:
In this case the direction of the dependency is: Driver => Car (the Driver object depends on the Car object).
Thankfully in real life each car has the interface: "steering wheel, pedals and gear shifter". A driver no longer depends on THE car, so a driver can drive ANY car:
Now TheDriver depends on the ICar interface, TheCar also depends on ICar interface - dependency is INVERTED:
I am no expert like others but will give a shot at explaining DIP with concept. At the heart of DIP is program to an interface i.e. your high level classes will rely on abstraction and your low level classes rely on the abstraction as well. for example
Lets say you define an abstraction called PhoneVendor i.e it can be samsung, apple, nokia etc.
Sorry about the code i haven't written Java for a while i.e it might have syntax error, but nonetheless its about the concept.
public abstract class PhoneVendor {
/**
* Abstract method that returns a list of phone types that each vendor creates.
*/
public abstract Vector getPhones(){ }
}
public class Samsung extends PhoneVendor{
public Vector getPhones(){ // return a list of phones it manufactures... }
}
public class PhoneFinder{
private PhoneVendor vendor;
public PhoneFinder(PhoneVendor vendor){ this.vendor = vendor;}
/**
*for example just return a concatnated string of phones
*/
public string getPhoneTypes(){
Vector ListOfPhones = PhoneVendor.getPhones();
return ListOfPhones;
}
}
As you can see PhoneFinder class depends on the abstraction not the implementation of the PhoneVendor. And your fundamental classes that implements the Abstraction are decoupled from the high level classes that use it. This makes the design really flexible where adding a new Low level classes wont break any previously written code since PhoneFinder is dependent on the abstraction not the implementation.
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.