I have the following builder/factory which abstracts a serializeable model from a class.
public class FooBarFactory : IFooBarFactory
{
public IFooModel Create(IFoo someClass)
{
// some complex model building code here
}
}
And I have a concrete implementation of IFooModel like so:
public interface IFooModel
{
string AbstractedData1 { get; }
string AbstractedData2 { get; }
int AbstractedData3 { get; }
}
public class ConcreteFooModel : IFooModel
{
public string AbstractedData1 { get; set; }
public string AbstractedData2 { get; set; }
public int AbstractedData3 { get; set; }
public bool ExtraData1 { get; set; }
}
Now arises the issue, I am struggling to find a way to not reference any concrete implementations in my builder/factory method, e.g.
public class FooBarFactory : IFooBarFactory
{
public IFooModel Create(IFoo someClass)
{
// some complex model building code here
var model = new ConcreteFooModel(someClass.data1, someClass.data1); // Aaargh
}
}
Something about this code is smelly to me, perhaps this is the only way, but I don't like the idea of being forced into referencing the concrete implementation to instantiate the data class, IFooModel.
This gets more complex if I now introduce another data holder interface into the IFooModel
public interface IFooModel
{
string AbstractedData1 { get; }
string AbstractedData2 { get; }
int AbstractedData3 { get; }
IBarData BarData { get; }
}
public interface IBarData
{
// some data in here
}
Forcing me then to create another concrete reference for the nested interface
public class FooBarFactory : IFooBarFactory
{
public IFooModel Create(IFoo someClass)
{
// some complex model building code here
IBarData barData = new ConcreteBarData();
IFooModel model = new ConcreteFooModel(someClass.data1, someClass.data1, barData);
}
}
Is there a better way to do this while still sticking to the SOLID principle and IoC?
What's important is to look at this from the perspective of the class that depends on IFooModel That's probably the first place where you want to prevent coupling.
You can accomplish that by injecting the factory into the class that needs it, like this:
public class NeedsFooFactory
{
private readonly IFooBarFactory _factory;
public NeedsFooFactory(IFooBarFactory fooBarFactory)
{
_factory = factory;
}
public void WhatEverThisClassDoes(IFoo foo)
{
var fooBar = _factory.Create(foo);
// Do something
}
}
Now the class that depends on the factory is decoupled from any implementation. You can substitute or mock another implementation of the factory that returns a different implementation of IFooModel.
Something to stop and think about at this point: Do you need an abstraction for ConcreteFooModel at all? If it's just a class that holds data then maybe you don't.
Getting back to the factory: Now that you can replace the factory with any implementation, this becomes less of a concern:
public class FooBarFactory : IFooBarFactory
{
public IFooModel Create(IFoo someClass)
{
// some complex model building code here
IBarData barData = new ConcreteBarData();
IFooModel model = new ConcreteFooModel(someClass.data1, someClass.data1, barData);
}
}
This implementation of the factory returns a specific concrete implementation of IFooModel. Is that bad? At some level classes are going to deal with concrete classes. In this case I think it's okay because this factory is doing what it's supposed to do. You don't have to worry that it's coupled to ConcreteFooModel. If you want a class that returns a different implementation you could create a different implementation of IFooBarFactory that returns a different implementation of IFooModel.
Again, this becomes even less of a concern if you question whether you need an abstraction for your foo model. Quite possibly the concrete class is all you need, and what matters is that you can have different implementations of the factory that populates it.
Related
I've got a large QueryModel class that overall looks like this:
public class QueryModel: IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
public interface IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
The IQueryModel is passed around when our API is processing a request. In our (very large) codebase, most code is effectful, so the model is both read and mutated freely.
I'm slowly separating pure and effectful code (in relation to this model) by introducing an immutable interface, to be passed to pure code only, like this:
// unchanged
public class QueryModel: IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
public interface IQueryModel : IQueryModelImmutable
{
public int Property1 { get; set; } // still implements both getters and setters
... ~100 more fields like this
}
public interface IQueryModelImmutable
{
public int Property1 { get; } // only has getters
... ~100 more fields like this
}
But now in each unit test, when mocking IQueryModel, I need to duplicate all set-ups like this:
Mock<IQueryModel> _queryModelMock = new(); // existing setup
_queryModelMock.Setup(m => m.Property1).Returns(100); // existing setup
_queryModelMock.As<IQueryModelImmutable>.Setup(m => m.Property1).Returns(100); // new setup
The production code is working fine, as the interface properties are simply inherited and resolved in the class, however Moq seems to require that the exact interface (and not its descendant) was mocked.
Is there any way to simplify these mock definitions, by e.g. enabling mock inheritance in some way?
EDIT: to explain why I need to use/mock both interfaces, here's a relevant piece of code under test:
// 1k LoC
public async Task LongStatefulMethod(IQueryModel model)
{
...
CallAnEffecfulMethod(model); // model mutated
...
// ComputeScorePure accepts the base interface - IQueryModelImmutable - as an argument
var computedScore = ComputeScorePure(model); // model not mutated
...
CallAnotherEffectfulMethod(model); // model mutated
...
}
You can workaround using Mock.Of<> or Mock.SetupAllProperties and setting the property manually:
// Mock<IQueryModel> mock = new ();
// mock.SetupAllProperties();
// var inherited = mock.Object;
var inherited = Mock.Of<IQueryModel>();
inherited.Property1 = 100;
IQueryModelImmutable #base = inherited;
Assert.AreEqual(100, inherited.Property1);
Assert.AreEqual(100, #base.Property1);
i have an abstract model named BetaModel that inherit its parent AlphaModel. Then
I have a bunch of request models that inherit the BetaModel and therefore naturally inherit AlphaModel, However I have the other bunch of response models which have to inherit the fields of BetaModel and do not need the fields in AlphaModel.
[Note: AlphaModel and BetaModel only contain some plain fields]
What is the elegant way to have the response models inherit the BetModel but ignore the AlphaModel?
Is it OK to turn the AlphaModel becomes an Interface, so that it only implemented in all the request models but not the response models?
So, you are basically contradicting the description with the "desired" architecture.
Also, always bare in mind that you don't decide architecture based on results ("Is it OK to turn the AlphaModel becomes an Interface"): your decisions are based on needs and responsibilities.
Interfaces
Think of that as a contract the classes are agreeing with. They don't hold any implementations and solely describe one contract the class implements
Abstract Classes
They are... Classes. As such, they don't define a contract, they define behaviours. And mostly, when defining an abstract class, you are looking for a abstract behaviour that you want children classes to inherit and/or give meaning to.
Your problem
You are saying some classes must inherit from AlphaModel and some others must NOT inherit from AlphaModel.
Therefore, you are saying that:
A certain class BetaModel1 inherits from AlphaModel and introduces some new members functionality.
Another class BetaModel2 should not expose any member from AlphaModel (which screams it doesn't inherit from AlphaModel) but also introduces the same members/functionality of BetaModel1
In other words, you are saying with all capital letters that BetaModel1 and BetaModel2 DO NOT INHERIT FROM THE SAME CLASS AlphaModel.
Now, back to our initial discussion. C# does not allow multiple inheritance (which looks like what you want to do). But there are strategies either to minimise re-writing code and/or enforce some implementations.
So, the "enforcing of implementation" is basically saying "I want this class to NECESSARILY provide certain functionality". Well... You need an interface for that
C#
public interface IBetaModel
{
string PropertyBeta { get; set; }
string MethodBeta();
}
There is also the AlphaModel
C#
public class AlphaModel
{
public string PropertyAlpha { get; set; }
public string MethodAlpha()
{
return "This is Alpha";
}
}
Now, your desired BetaModel1 (as described above) is quite simply inheriting from AlphaModel and implementing IBetaModel
C#
public class BetaModel1 : AlphaModel, IBetaModel
{
public string PropertyBeta { get; set; }
public string MethodBeta()
{
return "This is Beta?";
}
}
BetaModel2 it's just implementing IBetaModel, in which case:
C#
public class BetaModel2 : IBetaModel
{
public string PropertyBeta { get; set; }
public string MethodBeta()
{
return "This is Beta?";
}
}
The usage of the classes would be like:
C#
public void DoStuffWith(IBetaModel betaModel)
{
betaModel.PropertyBeta = "WOW, it works";
}
public void DoStuff()
{
var betaModel1 = new BetaModel1();
var betaModel2 = new BetaModel2();
AlphaModel betaModel1_ = new BetaModel1();
//AlphaModel betaModel2_ = new BetaModel2(); //won't compile
betaModel1.PropertyAlpha = "Test";
//betaModel2.PropertyAlpha = "Test"; //won't compile
DoStuffWith(betaModel1); //great!!!
DoStuffWith(betaModel2); //great too!!!
}
If this is only about data make every datapart an interface like...
public interface IAlphaModel
{
string SomeField { get; set; }
}
public interface IBetaModel
{
int AnotherField { get; set; }
}
public interface ISomeRequest : IAlphaModel, IBetaModel
{
bool YetAnotherField { get; set; }
}
class SomeRequest : ISomeRequest
{
public string SomeField { get; set; }
public int AnotherField { get; set; }
public bool YetAnotherField { get; set; }
}
public interface IAnotherRequest : IBetaModel
{
long TheUltimateField { get; set; }
}
class AnotherRequest : IAnotherRequest
{
public int AnotherField { get; set; }
public long TheUltimateField { get; set; }
}
Edit
Of course you can have the interfaces have more than one member if they are tied logically together.
I want to have some factory (doesn't matter if Abstract Factory pattern or Factory Method - looks like the second is specific form of the first one. In my case only one object should be created). The thing is that although created products are similar, they depends on some arguments.
How to prepare this architecture in compliance with design patterns?
Current approach below
public abstract class Product {}
public class MyProduct : Product
{
public bool Abc { get; set; }
}
public class YourProduct : Product {}
public abstract class ProductFactory
{
//in some cases parameter not in use
public abstract Product Create(HelpData additionalData);
}
public class MyProductFactory : ProductFactory
{
public override Product Create(HelpData additionalData)
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory : ProductFactory
{
//unused parameter
public override Product Create(HelpData additionalData)
{
return new YourProduct();
}
}
public class HelpData
{
public bool SomethingImportantForMyProduct { get; set; }
}
EDIT
I see it's not clear so will repeat.
Usually I'm not using patterns just because of using them. But this problem seems not to be border case. Looks rather quite frequent. Going further I believe there's design pattern suitable to this, but I'm not sure which one. For now looks like abstract factory is not right choice.
Don't use design-patterns because you're using design-patterns. Always have in mind when to use one and when not. In your circumstances at least the abstract factory-pattern is wrong, as it assumes all factories to work with the same parameters. So if you have different parameters you surely need different factories.
However there's no way for the abstract factory to guess how to get an instance of a HelpData in some case but not in the other, so either pass it to every abstract factory or completely omit this further abstraction and stay with two independent factories:
public abstract class Product {}
public class MyProduct : Product
{
public bool Abc { get; set; }
}
public class YourProduct : Product {}
public class MyProductFactory
{
public Product Create(HelpData additionalData)
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory
{
//unused parameter
public Product Create()
{
return new YourProduct();
}
}
public class HelpData
{
public bool SomethingImportantForMyProduct { get; set; }
}
Exposing a parameter only used within one factory to all factories isn't a good idea.
Besides this just imagine you don't have factories but any other classes that have a Create-method, where one needs a parameter, but the other one does not. Why should those two classes derive from the same base-class (in your case the abstract factory), when the don't have any common members? There's apparently no reason for this, so don't overcomplicate things just for the sake of using a pattern which doesn't fit.
Depending on where and how you retrieve additional data you could inject that data to the factory which will use it to construct the object:
public abstract class ProductFactory
{
public abstract Product Create();
}
public class MyProductFactory : ProductFactory
{
private HelpData additionalData;
public MyProductFactory(HelpData additionalData)
{
this.additionalData = additionalData;
}
public override Product Create()
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory : ProductFactory
{
public override Product Create()
{
return new YourProduct();
}
}
Instead of passing HelpData to constructor of a factory you could inject a service that knows how to retrieve HelpData specific to the object being created. You could pass some other parameter to Create method if it is used for both factories.
I have also googled a bit and found good answer that explains why not https://stackoverflow.com/a/6241219/2138959. Passing a dictionary or a type that has property of dictionary type is also and option but in such approaches client has too much knowledge of a type it want to be created to use abstract factory.
I am familiar with these patterns but still don't know how to handle following situation:
public class CarFactory
{
public CarFactory(Dep1,Dep2,Dep3,Dep4,Dep5,Dep6)
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(Dep1,Dep2,Dep3);
break;
case B:
return new Car2(Dep4,Dep5,Dep6);
break;
}
}
}
In general the problem is with amount of references that needs to be injected. It will be even worse when there are more cars.
First approach that comes to my mind is to inject Car1 and Car2 in factory constructor but it is against factory approach because factory will return always the same object. The second approach is to inject servicelocator but it's antipattern everywhere. How to solve it?
Edit:
Alternative way 1:
public class CarFactory
{
public CarFactory(IContainer container)
{
_container = container;
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return _container.Resolve<ICar1>();
break;
case B:
return _container.Resolve<ICar2>();
break;
}
}
}
Alternative way 2 (too hard to use because of too many of dependencies in tree):
public class CarFactory
{
public CarFactory()
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(new Dep1(),new Dep2(new Dep683(),new Dep684()),....)
break;
case B:
return new Car2(new Dep4(),new Dep5(new Dep777(),new Dep684()),....)
break;
}
}
}
Having a switch case statement inside of a factory is a code smell. Interestingly, you don't seem to be focusing on solving that issue at all.
The best, most DI friendly solution for this scenario is the strategy pattern. It allows your DI container to inject the dependencies into the factory instances where they belong, without cluttering up other classes with those dependencies or resorting to a service locator.
Interfaces
public interface ICarFactory
{
ICar CreateCar();
bool AppliesTo(Type type);
}
public interface ICarStrategy
{
ICar CreateCar(Type type);
}
Factories
public class Car1Factory : ICarFactory
{
private readonly IDep1 dep1;
private readonly IDep2 dep2;
private readonly IDep3 dep3;
public Car1Factory(IDep1 dep1, IDep2 dep2, IDep3 dep3)
{
this.dep1 = dep1 ?? throw new ArgumentNullException(nameof(dep1));
this.dep2 = dep2 ?? throw new ArgumentNullException(nameof(dep2));
this.dep3 = dep3 ?? throw new ArgumentNullException(nameof(dep3));
}
public ICar CreateCar()
{
return new Car1(this.dep1, this.dep2, this.dep3);
}
public bool AppliesTo(Type type)
{
return typeof(Car1).Equals(type);
}
}
public class Car2Factory : ICarFactory
{
private readonly IDep4 dep4;
private readonly IDep5 dep5;
private readonly IDep6 dep6;
public Car2Factory(IDep4 dep4, IDep5 dep5, IDep6 dep6)
{
this.dep4 = dep4 ?? throw new ArgumentNullException(nameof(dep4));
this.dep5 = dep5 ?? throw new ArgumentNullException(nameof(dep5));
this.dep6 = dep6 ?? throw new ArgumentNullException(nameof(dep6));
}
public ICar CreateCar()
{
return new Car2(this.dep4, this.dep5, this.dep6);
}
public bool AppliesTo(Type type)
{
return typeof(Car2).Equals(type);
}
}
Strategy
public class CarStrategy : ICarStrategy
{
private readonly ICarFactory[] carFactories;
public CarStrategy(ICarFactory[] carFactories)
{
this.carFactories = carFactories ?? throw new ArgumentNullException(nameof(carFactories));
}
public ICar CreateCar(Type type)
{
var carFactory = this.carFactories
.FirstOrDefault(factory => factory.AppliesTo(type));
if (carFactory == null)
{
throw new InvalidOperationException($"{type} not registered");
}
return carFactory.CreateCar();
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6)
});
// And then once it is injected, you would simply do this.
// Note that you could use a magic string or some other
// data type as the parameter if you prefer.
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
Note that because there is no switch case statement, you can add additional factories to the strategy without changing the design, and each of those factories can have their own dependencies that are injected by the DI container.
var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6),
new Car3Factory(dep7, dep8, dep9)
});
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
var car3 = strategy.CreateCar(typeof(Car3));
Answering your comment about code example with Composition Root.
You can create following and this is not a Service Locator.
public class CarFactory
{
private readonly Func<Type, ICar> carFactory;
public CarFactory(Func<Type, ICar> carFactory)
{
this.carFactory = carFactory;
}
public ICar CreateCar(Type carType)
{
return carFactory(carType);
}
and this is how look your Composition Root using Unity DI container :
Func<Type, ICar> carFactoryFunc = type => (ICar)container.Resolve(type);
container.RegisterInstance<CarFactory>(new CarFactory(carFactoryFunc));
I answered a similar question some time ago. Basically it's all about your choice. You have to choose between verbosity (which gives you more help from a compiler) and automation, which allows you to write less code but is more prone to bugs.
This is my answer supporting verbosity.
And this is also a good answer that supports automation.
EDIT
I believe the approach you consider wrong is actually the best. Truth being said, usually there won't so many dependencies in there. I like this approach because it's very explicit and rarely results in runtime errors.
Alternative way 1:
This one is bad. It's actually a service locator, which is considered an anti-pattern.
Alternative way 2
Like you wrote, it's not easy to use if mixed with IOC containter. However in some case a similar approach (poor man's DI) can be useful.
All in all, I wouldn't bother having "many" dependencies in your factories. It's a simple, declarative code. It takes seconds to write and can save you hours of struggling with runtime errors.
I would consider giving the dependencies a good structure so you can utilize something similar to Wiktor's answer, but I would abstract the Car factory itself. Then, you don't use the if..then structure.
public interface ICar
{
string Make { get; set; }
string ModelNumber { get; set; }
IBody Body { get; set; }
//IEngine Engine { get; set; }
//More aspects...etc.
}
public interface IBody
{
//IDoor DoorA { get; set; }
//IDoor DoorB { get; set; }
//etc
}
//Group the various specs
public interface IBodySpecs
{
//int NumberOfDoors { get; set; }
//int NumberOfWindows { get; set; }
//string Color { get; set; }
}
public interface ICarSpecs
{
IBodySpecs BodySpecs { get; set; }
//IEngineSpecs EngineSpecs { get; set; }
//etc.
}
public interface ICarFactory<TCar, TCarSpecs>
where TCar : ICar
where TCarSpecs : ICarSpecs
{
//Async cause everything non-trivial should be IMHO!
Task<TCar> CreateCar(TCarSpecs carSpecs);
//Instead of having dependencies ctor-injected or method-injected
//Now, you aren't dealing with complex overloads
IService1 Service1 { get; set; }
IBuilder1 Builder1 { get; set; }
}
public class BaseCar : ICar
{
public string Make { get; set; }
public string ModelNumber { get; set; }
public IBody Body { get; set; }
//public IEngine Engine { get; set; }
}
public class Van : BaseCar
{
public string VanStyle { get; set; }
//etc.
}
public interface IVanSpecs : ICarSpecs
{
string VanStyle { get; set; }
}
public class VanFactory : ICarFactory<Van, IVanSpecs>
{
//Since you are talking of such a huge number of dependencies,
//it may behoove you to properly categorize if they are car or
//car factory dependencies
//These are injected in the factory itself
public IBuilder1 Builder1 { get; set; }
public IService1 Service1 { get; set; }
public async Task<Van> CreateCar(IVanSpecs carSpecs)
{
var van = new Van()
{
//create the actual implementation here.
};
//await something or other
return van;
}
}
I didn't list it, but you can implement multiple types of cars and their corresponding factories now and use DI to inject whatever you need.
First, you have a concrete factory, an IoC container could be an alternative rather than something to help you there.
Then, just refactor the factory to not to expect a full possible parameter list in the factory constructor. This is the primary issue - why are you passing so many parameters if the factory method doesn't need them?
I would rather pass specific parameters to the factory method
public abstract class CarFactoryParams { }
public class Car1FactoryParams : CarFactoryParams
{
public Car1FactoryParams(Dep1, Dep2, Dep3)
{
this.Dep1 = Dep1;
...
}
public class Car2FactoryParams
...
public class CarFactory
{
public ICar CreateCar( CarFactoryParams params )
{
if ( params is Car1FactoryParams )
{
var cp = (Car1FactoryParams)params;
return new Car1( cp.Dep1, cp.Dep2, ... );
}
...
if ( params is ...
By encapsulating the parameter list in a specific class you just make the client provide exactly these parameters that are required for specific factory method invocation.
Edit:
Unfortunately, it was not clear from your post what are these Dep1, ... and how you use them.
I suggest following approach then that separates the factory provider from actual factory implementation. This approach is known as the Local Factory pattern:
public class CarFactory
{
private static Func<type, ICar> _provider;
public static void SetProvider( Func<type, ICar> provider )
{
_provider = provider;
}
public ICar CreateCar(type)
{
return _provider( type );
}
}
The factory itself doesn't have any implementation, it is here to set the foundation to your domain API, where you want your car instances to be created with this API only.
Then, in the Composition Root (somewhere near the starting point of the app where you configure your actual container), you configure the provider:
CarFactory.SetProvider(
type =>
{
switch ( type )
{
case A:
return _container.Resolve<ICar1>();
case B:
return _container.Resolve<ICar2>();
..
}
);
Note that this example implementation of the factory's provider uses a delegate but an interface could also be used as a specification for an actual provider.
This implementation is basically #1 from your edited question, however, it doesn't have any particular downsides. The client still calls:
var car = new CarFactory().CreareCar( type );
Many DI containers support the notion of named dependencies.
E.g. (Structuremap syntax)
For<ICar>().Use<CarA>().Named("aCar");
Container.GetNamedInstance("aCar") // gives you a CarA instance
If you use something like a convention, a rule how the name is derived from the concrete car type itself, you have a situation where you don't need to touch the factory anymore when you extend the system.
Using this in a factory is straightforward.
class Factory(IContainer c) {
public ICar GetCar(string name) {
Return c.GetNamedInstance(name);
}
}
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
}