I have a business model TodoItem. I have an API that gives me todoitems. So, I have a corresponding TodoItemModel for each controller (let's name it TodoItemDTO).
The TodoItemDTO class should be able to load itself from a TodoItem business class. So, usually, we would write a static method on the TodoItemDTO class TodoItemDTO FromTodoItem(TodoItem todoItem).
I would like to define an interface for such classes. But unfortunately I can't define a static method in an interface... (note: I use the latest C# version, so, finally, I do, but I should define it... however each class should define its static method)
Here is what I tried:
public interface IDtoModel<TBussinesModel, TDtoModel>
{
TDtoModel FromBusinessModel(TBussinesModel businessObject);
}
public class ToDoItemDTO : IDtoModel<ToDoItem, ToDoItemDTO>
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public bool IsDone { get; private set; }
public ToDoItemDTO FromBusinessModel(ToDoItem businessObject)
{
return new ToDoItemDTO()
{
Id = businessObject.Id,
Title = businessObject.Title,
Description = businessObject.Description,
IsDone = businessObject.IsDone
};
}
}
The only 'problem' here is I have a class method that should be, normally, a static method.
So, by eg, when I define a generic controller, I need to create new objects without any need:
[Route("api/[controller]")]
[ApiController]
public abstract class BaseApiController<TBussinesModel, TDtoModel> : Controller
where TBussinesModel : BaseEntity
where TDtoModel : IDtoModel<TBussinesModel, TDtoModel>, new()
{
protected readonly IRepository _repository;
public BaseApiController(IRepository repository) { _repository = repository; }
[HttpGet("{id:int}")]
public async Task<IActionResult> GetById(int id)
{
var businessObject = await _repository.GetByIdAsync<TBussinesModel>(id);
//
// here bellow, I need to create a new object
//
var dtoObject = (new TDtoModel()).FromBusinessModel(businessObject);
return Ok(dtoObject);
}
[HttpPost]
public abstract Task<IActionResult> Post([FromBody] TDtoModel item);
}
There are lots of options, none of them perfect.
Personally, I would start by turning your factory method into a constructor of the DTO;
public ToDoItemDTO(ToDoItem businessObject)
{
Id = businessObject.Id;
Title = businessObject.Title;
Description = businessObject.Description;
IsDone = businessObject.IsDone;
}
You could define a factory class for each DTO. You could use Activator.CreateInstance to dynamically call the constructor at runtime.
Or you can locate the constructor with reflection, build an Expression tree and compile it.
static Func<TBussinesModel, TDtoModel> GetFactory<TBussinesModel, TDtoModel>()
{
var p = Expression.Parameter(typeof(TBussinesModel), "p");
return Expression.Lambda<Func<TBussinesModel, TDtoModel>>(
Expression.New(
typeof(TDtoModel).GetConstructor(new Type[] { typeof(TBussinesModel) }),
p
),
p)
.Compile();
}
Related
6 Years have passed since this question was made and I was expecting to have an easy solution today.. but seems not.
NOTE: please read the other question to understand the concept:
After a few minutes I tried to implement an easy example and I've almost accomplished it. Meanwhile I still see some problems. And I was wondering if someone has ideas on how to make it better.
Using .NET 6 (code bellow).
Issue 1: I don't like the fact that the generics where we say, use TTarget as User, we also need to pass the T ID type.... why by passing User is not enought for the compiler to know the ID data type? Example: class UserService : IBaseDBOperation1<User, Guid> why not class UserService : IBaseDBOperation1<User> ?
Issue 2: I understand that now we are allowed to have interfaces with methods with code, but why do we still need to define the variable type exactly with both data types and using var is not enough? Well, we can use var, but then the methods are not visible.
instead of: IBaseDBOperation1<User, Guid> serviceU1 = new UserService(); ........ var serviceU2 = new UserService(); ...... this second variable will not see the other methods.
Final note: Everything would be so much easier if C# would allow us to extend a class with more than one other abstract class.... (as of today we are limited to 1).
Objective: Accomplish what was asked in the question made 6 years ago.... in other words.... avoid copy/paste, and somehow "inject/associate/register/define" more than one "operation class" into a service.... those "operation classes" will be reused a lot in multiple different services.... and I do want to have a "clean/pretty" way of setting this up, but at the same time, the consumer should not worry about "lower/deeper "lever inheritance generics.
Code
public abstract class BaseDBEntry<T> where T : struct
{
protected BaseDBEntry()
{
CreatedOn = DateTime.Now;
}
public T Id { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
}
public class User : BaseDBEntry<Guid>
{
public User() { Id = Guid.NewGuid(); }
public string Name { get; set; }
}
public class Color : BaseDBEntry<long>
{
public Color() { Id = DateTime.Now.Ticks; }
public string RGB { get; set; }
}
Services
public interface IBaseDBOperation1<in TTarget, out T>
where TTarget : BaseDBEntry<T> where T : struct
{
public bool IsValid(TTarget model) { return true; }
T GiveMeId(TTarget model) { return model.Id; }
}
public interface IBaseDBOperation2<in TTarget, T>
where TTarget : BaseDBEntry<T> where T : struct
{
public bool IsValidToDoSomethingElse(TTarget model) { return false; }
}
public class UserService : IBaseDBOperation1<User, Guid>, IBaseDBOperation2<User, Guid> { }
public class ColorService : IBaseDBOperation1<Color, long>, IBaseDBOperation2<Color, long> { }
Consumer
public class Consumer
{
public void Run()
{
IBaseDBOperation1<User, Guid> serviceU1 = new UserService();
IBaseDBOperation2<User, Guid> serviceU2 = new UserService();
var u = new User { Name = "Carl" };
var resU1 = serviceU1.IsValid(u);
var resU2 = serviceU1.GiveMeId(u);
var resU3 = serviceU2.IsValidToDoSomethingElse(u);
var serviceU3 = new UserService();
//serviceU3.XXXXX() --> has no information about the methods we need
IBaseDBOperation2<Color, long> serviceC1 = new ColorService();
var c = new Color { RGB = "#FFFFFF" };
var resC1 = serviceC1.IsValidToDoSomethingElse(c);
var adasda = "";
}
}
var consumer = new Consumer();
consumer.Run();
I will start with small remark - please try to follow standard naming conventions, in this case this one:
Interface names start with a capital I.
As for the issues:
Issue 1: I don't like the fact that the generics where we say, use TTarget as User, we also need to pass the T ID type.
Not much has changed here for the last 6 years, interface BaseDBOperation1<TTarget, T>.. still requires 2 generic type parameters and you can still have an interface with one type parameter, i.e. interface BaseDBOperation1<TTarget> which will be ambiguous for the compiler (so adding interface BaseDBOperation1<TTarget> will become a breaking change, which is a concern if those classes are distributed as library).
Possibly something like this could be achieved with something like higher-kinded types or similar language feature but ATM it is not available in C#.
Related issues to track:
First-class generic method / First-class polymorphism / Rank-N types
Higher Kinded Polymorphism / Generics on Generics
"Opaque" parameters
Existential types for interfaces and abstract types
partial type inference
Issue 2: ... this second variable will not see the other methods.
This is by design (default interface methods draft spec):
Note that a class does not inherit members from its interfaces; that is not changed by this feature:
interface IA
{
void M() { WriteLine("IA.M"); }
}
class C : IA { } // OK
new C().M(); // error: class 'C' does not contain a member 'M'
In order to call any method declared and implemented in the interface, the variable must be the type of the interface
i.e. for var serviceU2 = new UserService(); you will need to cast to corresponding interface:
var resU1 = ((BaseDBOperation1<User, Guid>)serviceU2).IsValid(u);
Another reason for such behaviour can be similar to the so called brittle/fragile base class problem.
Personally I'm not a big fan of this feature both conceptually and due to some corner cases (for example this one).
As for an approach to implement such functionality and reducing code written manually (if you have A LOT of such repositories) - you can look at some compile time code generation with source generators but this is not definitely an easy option. At least for the first time.
Would the following work for you? Essentially making the User and the Color the holder of the service operations.
https://dotnetfiddle.net/zsjZfQ
using System;
var user = new User();
var color = new Color();
Console.WriteLine(user.DbOperation1.IsValid());
Console.WriteLine(user.DbOperation2.IsValidToDoSomethingElse());
Console.WriteLine(user.DbOperation3.ThisIsOnlyAvailableToSome());
Console.WriteLine(color.DbOperation1.IsValid());
Console.WriteLine(color.DbOperation2.IsValidToDoSomethingElse());
var userAsBaseDbEntry = (BaseDBEntry<Guid>)user;
Console.WriteLine(userAsBaseDbEntry.DbOperation1.IsValid());
Console.WriteLine(userAsBaseDbEntry.DbOperation2.IsValidToDoSomethingElse());
public abstract class BaseDBEntry<T> where T : struct
{
public abstract IDbOperation1<T> DbOperation1 { get; init; }
public abstract IDbOperation2<T> DbOperation2 { get; init; }
public T Id { get; init; }
public DateTime CreatedOn { get; init; } = DateTime.Now;
public DateTime? DeletedOn { get; init; }
}
public class User : BaseDBEntry<Guid>
{
public string Name { get; init; }
override public sealed IDbOperation1<Guid> DbOperation1 { get; init; }
override public sealed IDbOperation2<Guid> DbOperation2 { get; init; }
public IDbOperation3 DbOperation3 { get; }
public User()
{
DbOperation1 = new DbOperation1Impl<Guid>(this);
DbOperation2 = new DbOperation2Impl<Guid>(this);
DbOperation3 = new DbOperation3Impl(this);
Id = Guid.NewGuid();
}
}
public interface IDbOperation3
{
bool ThisIsOnlyAvailableToSome();
}
public class DbOperation3Impl : IDbOperation3
{
private readonly BaseDBEntry<Guid> _entry;
public DbOperation3Impl(BaseDBEntry<Guid> entry)
{
_entry = entry;
}
public bool ThisIsOnlyAvailableToSome() => !_entry.DbOperation1.IsValid();
}
public class Color : BaseDBEntry<long>
{
override public sealed IDbOperation1<long> DbOperation1 { get; init; }
override public sealed IDbOperation2<long> DbOperation2 { get; init; }
public string Rgb { get; init; }
public Color()
{
DbOperation1 = new DbOperation1Impl<long>(this);
DbOperation2 = new DbOperation2Impl<long>(this);
Id = DateTime.Now.Ticks;
}
}
public interface IDbOperation1<T> where T : struct
{
bool IsValid();
}
public interface IDbOperation2<T> where T : struct
{
bool IsValidToDoSomethingElse();
}
class DbOperation1Impl<T> : IDbOperation1<T> where T : struct
{
private readonly BaseDBEntry<T> _entry;
public DbOperation1Impl(BaseDBEntry<T> entry)
{
_entry = entry;
}
public bool IsValid() => _entry.CreatedOn < DateTime.Now;
}
class DbOperation2Impl<T> : IDbOperation2<T> where T : struct
{
private readonly BaseDBEntry<T> _entry;
public DbOperation2Impl(BaseDBEntry<T> entry)
{
_entry = entry;
}
public bool IsValidToDoSomethingElse() => _entry.DeletedOn != null;
}
I have a project involving a webshop for different kinds of products. From what I understand, if you have multiple classes that inherit from one base class, the factory design pattern is the way to go. I only have trouble deciding where to put the logic for actually deciding which factory to use.
I have created classes and factory classes for the different kinds of products like so.
public class Product
{
public int ID { get; protected set; }
public string Name { get; set; }
public ProductType Type { get; private set; }
public Product(int id)
{
ID = id;
Populate();
}
public virtual void CompleteOrder()
{
//SendMailToSupplier();
}
private void Populate()
{
//database stuff including setting the type
}
}
public class DigitalProduct : Product
{
public DigitalAsset ProductAsset { get; private set; }
public DigitalProduct(int id, DigitalAsset asset) : base(id)
{
ProductAsset = asset;
}
public override void CompleteOrder()
{
base.CompleteOrder();
//SendAssetToUser();
}
}
public class PrintProduct : Product
{
public PrintInformation Information { get; private set; }
public PrintProduct(int id, PrintInformation information) : base(id)
{
Information = information;
}
public override void CompleteOrder()
{
base.CompleteOrder();
//PreparePrintingFlle();
}
}
public abstract class ProductFactory
{
public abstract Product CreateProduct(int id);
}
public class GenericProductFactory : ProductFactory
{
public override Product CreateProduct(int id)
{
return new Product(id);
}
}
public class DigitalProductFactory : ProductFactory
{
public override Product CreateProduct(int id)
{
DigitalAsset asset = GetDigitalAsset(id);
return new DigitalProduct(id, asset);
}
private DigitalAsset GetDigitalAsset(int id)
{
DigitalAsset asset = new DigitalAsset();
//IO stuff
return asset;
}
}
public class PrintProductProductFactory : ProductFactory
{
public override Product CreateProduct(int id)
{
PrintInformation information = GetPrintInformation(id);
return new PrintProduct(id,information);
}
private PrintInformation GetPrintInformation(int id)
{
PrintInformation information = new PrintInformation();
//database stuff
return information;
}
}
Now when an order is completed an event is triggered.
public void OrderCompleted(int orderId, List<int> productIds);
So here I have a list of int's from which I want to make product object so I can call the
CompleteOrder function on each of them. The problem is to know the type of the product I need to get the product type from the database which is filled in the populate function.
What I could do is create a function public ProductFactory GetFactory(int id) in the ProductFactory. But then the factory is can not be an abstract class.
Another option would be creating a function public static Product GetProduct(int id) in the product class. Which then first figures out which factory to use and the returns the created product.
But both of this options feel weird. Am I missing something? Or is one of these the actual way to go?
Cheers.
So skip the Populate function in the Product class. That is the duties of the factory to do. And I would go with one factory class to create all types of products. (The factory can if needed call other classes to help create the product)
Something like:
public class ProductFactory
{
public Product GetProductById(int id)
{
var dbProduct = FetchFromDb(id);
switch(dbProduct.Type)
{
case "Print"
return CreatePrintProduct(dbProduct);
case "Digital"
return CreateDigitalProduct(dbProduct);
}
}
private DigitalProduct CreateDigitalProduct(DbEntity dbProduct)
{
var product = new DigitalProduct(dbProduct.Id);
//Initialize the product
return product;
}
//You might also want a batch function to avoid calling the database for each product.
public IEnumerable<Product> GetProductByIds(IEnumerable<int> ids)
{
var dbProducts = FetchFromDb(ids);
...
}
}
Eh, just don't over think it. Design patterns should be tools you wield to create your code, if I read your question correctly, I think you are more in a state of the design pattern wielding you.
So unless the pattern helps you, do not over complicate your code with it.
That said, If you do choose to go for a pattern, your situation seems simple enough to go for Magnus's solution.
look at this example of factory method design pattern: http://jayeshtanna.azurewebsites.net/2018/11/25/factory-method-design-pattern/
I am trying to better understand the use of the factory method pattern and adhering to SOLID principles and I am not sure if my implementation is correct for the following reasons:
The dependencies my IBankAccountAddOnService implementations need (instantiated in my factory) the larger my BankAccountAddOnFactory constructor is going to get. Shouldn't each IBankAccountAddOnService be responsible for its own dependencies via DI?
In the constructor params for each IBankAccountAddOnService implementation not only do they contain their dependencies but also the concrete type of IBankAccountAddOn specific to that service (e.g. CreditCardAddOn for CreditCardAddOnService). This feels wrong and is why I can't use DI to set them for each service. How could I get the BuildAddOn method to take in the relevant concrete IBankAccountAddOn instead?
Does the switch statement violate the Open Closed Principle or is it ok within a factory? If there were many more bank addons in future, the switch statement may become very large?
IBankAccountAddOn and it's implementations (there may be many of these)
public interface IBankAccountAddOn
{
int Id { get; }
}
public class CreditCardAddOn : IBankAccountAddOn
{
public int Id { get; }
public int CustomerId { get; set; }
public double Limit { get; set; }
public double BalanceTransfer { get; set; }
}
public class TravelInsuranceAddOn : IBankAccountAddOn
{
public int Id { get; }
public int CustomerId { get; set; }
public DateTime Start { get; set; }
public int? MonthsDuration { get; set; }
}
IBankAccountAddOnService that my factory creates dependent upon IBankAccountAddOn
Note - The IExternal... interfaces are from 3rd party libraries.
public interface IBankAccountAddOnResult
{
bool Success { get; set; }
List<string> Errors { get; set; }
}
public class BankAccountAddOnResult : IBankAccountAddOnResult
{
public bool Success { get; set; }
public List<string> Errors { get; set; }
}
public interface IBankAccountAddOnService
{
IBankAccountAddOnResult BuildAddOn();
}
public class CreditCardAddOnService : IBankAccountAddOnService
{
private readonly IExternalCreditCardService _creditCardService;
private readonly IRepository _repository;
private readonly CreditCardAddOn _creditCardAddOn;
public CreditCardAddOnService(IExternalCreditCardService creditCardService, IRepository repository, CreditCardAddOn creditCardAddOn)
{
_creditCardService = creditCardService;
_repository = repository;
_creditCardAddOn = creditCardAddOn;
}
public IBankAccountAddOnResult BuildAddOn()
{
var customerDetails = _repository.GetCustomer(_creditCardAddOn.CustomerId);
if (!customerDetails.CanApplyCreditCards)
{
return new BankAccountAddOnResult
{
Success = false,
Errors = new List<string>{
"Customer cannot apply for credit cards"
}
};
}
var result = _creditCardService.Apply(_creditCardAddOn);
return result;
}
}
public class TravelInsuranceAddOnService : IBankAccountAddOnService
{
private readonly IExternalTravelInsuranceService _travelInsuranceService;
private readonly TravelInsuranceAddOn _travelInsuranceAddOn;
public TravelInsuranceAddOnService(IExternalTravelInsuranceService travelInsuranceService, TravelInsuranceAddOn travelInsurance)
{
_travelInsuranceService = travelInsuranceService;
_travelInsuranceAddOn = travelInsurance;
}
public IBankAccountAddOnResult BuildAddOn()
{
var result = _travelInsuranceService.Apply(_travelInsuranceAddOn.CustomerId, _travelInsuranceAddOn.MonthsDuration, _travelInsuranceAddOn.Start);
return result;
}
}
Factory implementation
public interface IBankAccountAddOnFactory
{
IBankAccountAddOnService Create(IBankAccountAddOn addOn);
}
public class BankAccountAddOnFactory : IBankAccountAddOnFactory
{
private readonly IExternalCreditCardService _creditCardService;
private readonly IExternalTravelInsuranceService _travelInsuranceService;
private readonly IRepository _repository;
public BankAccountAddOnFactory(
IExternalCreditCardService creditCardService,
IExternalTravelInsuranceService travelInsuranceService,
IRepository repository
)
{
_creditCardService = creditCardService;
_travelInsuranceService = travelInsuranceService;
_repository = repository;
}
public IBankAccountAddOnService Create(IBankAccountAddOn addOn)
{
switch (addOn)
{
case CreditCardAddOn creditCard:
return new CreditCardAddOnService(_creditCardService, _repository, creditCard);
case TravelInsuranceAddOn travelInsurance:
return new TravelInsuranceAddOnService(_travelInsuranceService, travelInsurance);
//Many other addon cases
default:
throw new ArgumentOutOfRangeException();
}
}
}
Service that creates add ons for customers
public class BankAccountAddOnService
{
private IBankAccountAddOnFactory _bankAddOnFactory;
public BankAccountAddOnService(IBankAccountAddOnFactory bankAddOnFactory)
{
_bankAddOnFactory = bankAddOnFactory;
}
public IBankAccountAddOnResult Apply(IBankAccountAddOn addOn)
{
var applyService = _bankAddOnFactory.Create(addOn);
var response = applyService.BuildAddOn();
//Do something with response
return response;
}
}
The dependencies my IBankAccountAddOnService implementations need (instantiated in my factory) the larger my BankAccountAddOnFactory constructor is going to get. Shouldn't each IBankAccountAddOnService be responsible for its own dependencies via DI?
I don't understand "each [service] be responsible for its own dependencies via DI." The whole point of DI is that classes are not responsible for their own dependencies-- the code that instantiates the class is.
And yes it is normal to have a constructor with more and more arguments as dependencies are added. If you have trouble with this, see Constructor injection: How many dependencies is too many?.
In the constructor params for each IBankAccountAddOnService implementation not only do they contain their dependencies but also the concrete type of IBankAccountAddOn specific to that service (e.g. CreditCardAddOn for CreditCardAddOnService). This feels wrong and is why I can't use DI to set them for each service. How could I get the BuildAddOn method to take in the relevant concrete IBankAccountAddOn instead?
It's okay to inject a concrete type, obviously, but the class receiving the injection should not rely on it. Instead, define an interface for the things it relies on, and add that interface to the concrete type. It's OK if that interface contains all the concrete type's members.
Example:
public interface IBankAccountAddOnService
{
IBankAccountAddOnResult BuildAddOn();
}
public interface ICreditCardAddOnService : IBankAccountAddOnService
{
int CustomerId { get; }
}
public class CreditCardAddOnService : ICreditCardAddOnService
{
public CreditCardAddOnService(IExternalCreditCardService creditCardService, IRepository repository, ICreditCardAddOn creditCardAddOn)
{
//etc
Does the switch statement violate the Open Closed Principle or is it ok within a factory? If there were many more bank addons in future, the switch statement may become very large?
No, it does not violate OCP in and of itself.
If the list gets very large, you can implement as a map instead, e.g.
var map = new Dictionary<Type,Func<IBankAccountAddOnService>>
{
{ typeof(CreditCardAddOn), () => new CreditCardAddOnService(_creditCardService, _repository, creditCard) },
{ typeof(TravelInsuranceAddOn), () => new TravelInsuranceAddOnService(_travelInsuranceService, travelInsurance) }
}
With the map in place, you can do this:
public IBankAccountAddOnService Create(IBankAccountAddOn addOn)
{
return map[addOn.GetType()]();
}
I'm having problem in passing parameter dynamically to class constructor using simple injector.
I have following code structure.
Controller example:
public class HomeController : Controller
{
private readonly ICheckService _checkService;
public HomeController(ICheckService checkService)
{
_checkService= checkService;
}
// GET: Home
public ActionResult Index()
{
var list = _checkService.GetAll();
return View(list);
}
}
Service layer (in this layer I need to pass the two constructor parameter for CheckRepository<T> which is implementing ICheckRepository<T>. How do I achieve this using simple injector? I tried but not getting solution around. One example in order to achieve would be really grateful)
public interface ICheckService
{
List<CheckType> GetAll();
}
public class CheckService : ICheckService
{
private readonly ICheckRepository<CheckType> _checkRepository;
public CheckService(ICheckRepository<CheckType> checkRepository)
{
_checkRepository= checkRepository;
}
public List<T> GetAll()
{
return _checkRepository.GetAll().ToList();
}
}
Repository Layer:
public abstract class RepositoryBase<T> where T : class
{
public string Types { get; set; }
public string Segment { get; set; }
public RepositoryBase(string type)
{
Types = type;
}
public RepositoryBase(string type, string segment)
{
Types = type;
Segment = segment;
}
}
public interface ICheckRepository<T> where T : class
{
IEnumerable<T> GetAll();
}
public class CheckRepository<T> : RepositoryBase<T>, ICheckRepository<T> where T : class
{
public CheckRepository(string types, string segment)
: base(types, segment)
{
}
public IEnumerable<T> GetAll()
{
var list = new List<T>();
using (DbAccess dbAccess = new DbAccess(ConnectionString, DatabaseType.SqlServer))
{
return dbAccess.ExecuteReader<T>(StoredProc, CommandType.StoredProcedure).ToList();
}
}
}
My Simple Injector initializer class:
public static void InitializeInjector()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
container.Register(typeof(IFilterRepository<>), typeof(FilterRepository<>));
//Here is where I am struggling to bind dynamic constructor parameter registering
}
Does anyone have any solution for the above code?
Thanks again.
In case the parameters are fixed to the specific closed-generic types, you should make the registrations as follows:
c.Register<ICheckRepo<Customer>>(() => new CheckRepository<Customer>(constr, "cust_sp"));
c.Register<ICheckRepo<Order>>(() => new CheckRepository<Order>(constr, "order_sp"));
c.Register<ICheckRepo<Product>>(() => new CheckRepository<Product>(constr, "prod_sp"));
// more registrations here
In case your repository mixes dependencies with configuration values, you can also use contextual registration mixed with the registration of the open-generic type:
// Registrations
// One registration for the open generic type
c.Register(typeof(ICheckRepository<>), typeof(CheckRepository<>));
// One registration for the connection string (assuming you only have one)
container.RegisterConditional(typeof(string), CreateStringConstant(constr),
c => c.Consumer.Target.Name == "connectionString");
// Conditional registrations for each closed ICheckRepository<T>
RegisterStoredProcForCheckRepository<Customer>("cuts_sp");
RegisterStoredProcForCheckRepository<Order>("order_sp");
RegisterStoredProcForCheckRepository<Product>("prod_sp");
// more registrations here
// Helper methods
Registration CreateStringConstant(string value) =>
Lifestyle.Singleton.CreateRegistration(typeof(string), () => value, container);
void RegisterStoredProcForCheckRepository<TEntity>(string spName) {
container.RegisterConditional(typeof(string), CreateStringConstant(container, spName),
c => c.Consumer.Target.Name == "segment"
&& c.Contumer.ImplementationType == typeof(CheckRepository<TEntity>));
}
In case the connection string or stored procedure varies per request, you should change the design, as explained here.
I have two versions of a factory class designed based on the article
http://www.oodesign.com/factory-pattern.html
public abstract class Employee
{
public string Name { get; set; }
protected string Role { get; set; }
public abstract string GetRole();
}
public class Manager : Employee
{
public Manager()
{
Role = "MGR";
}
public override string GetRole()
{
return this.Role;
}
}
Version 1: Simple, Violates Open Close Principle
Need to change SimpleEmployeeFactory every time, when I add a new concrete class
public class SimpleEmployeeFactory
{
public static Employee GetEmployee(int typeId)
{
switch (typeId)
{
case 1:
return new Manager();
case 2:
return new TechnicalLead();
default:
return null; //if the id doesn't have any
}
}
}
Version 2:
Refactored Factory, still needs a Concrete Class creation, before we use factory call
public abstract class Employee
{
public string Name { get; set; }
protected string Role { get; set; }
public abstract string GetRole();
public abstract Employee createEmployee();
}
public class ChiefTechnologyOfficer : Employee
{
public ChiefTechnologyOfficer()
{
this.Role = "CTO";
}
static ChiefTechnologyOfficer()
{
RefactoredFactory.Instance.registerEmployee(5, new ChiefTechnologyOfficer());
}
public override string GetRole()
{
return this.Role;
}
public override Employee createEmployee()
{
return new ChiefTechnologyOfficer();
}
}
Factory
class RefactoredFactory
{
private static readonly RefactoredFactory instance = new RefactoredFactory();
static RefactoredFactory()
{
}
private RefactoredFactory()
{
}
public static RefactoredFactory Instance
{
get
{
return instance;
}
}
private Dictionary<int, Employee> registeredEmployees = new Dictionary<int, Employee>();
public void registerEmployee(int typeId, Employee employeeInst)
{
registeredEmployees.Add(typeId, employeeInst);
}
public Employee createEmployee(int typeId)
{
return ((Employee)registeredEmployees[typeId]).createEmployee();
}
}
Client
Employee emp = SimpleEmployeeFactory.GetEmployee(1);
Activator.CreateInstance(typeof(ChiefTechnologyOfficer)); //Avoid
Employee empFNoR = RefactoredFactory.Instance.createEmployee(5);
You can see Activator.CreateInstance(typeof(ChiefTechnologyOfficer)) call to make the concrete classes to register themselves with the Factory. Otherwise we cant retrieve the object
Is there a way to create a Factory class with out violating OCP principle & with out creating an object like the one I used in RefactoredFactory class?
It looks like the typeId suffers from Feature Envy. Instead, define a polymorphic type to capture the type; e.g. an interface:
public interface IEmployeeType
{
Employee Create()
}
Now you can define e.g. a ManagerType, and a TechnicalLeadType, etc. Example:
public class ManagerType : IEmployeeType
{
public Employee Create()
{
return new Manager();
}
}
This is essentially an Abstract Factory, and it has the advantage that you can always create a new implementation when you need to create a new sub-type.
If you're at the boundary of a system, and must translate a primitive value like an integer to a polymorphic value, you can use one of the Role Hint patterns - particularly Metadata, Role Interface, or (my favourite) Partial Type Name.
Client
Given an IEmployeeType instance employeeType, a client would simply go:
Employee emp = employeeType.Create();
Thala,
Instead of using static constructor,register method to populate dictionary of Types.
You can use config based solution like .net DbProviderFactory, to register all types.
<EmployeeFactories>
<add name="manger" type="Manager, EmployeeAssmbly" />
..
</EmployeeFactories>