Implementation of factory method pattern with dependencies - c#

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()]();
}

Related

C# how to "register" class "plug-ins" into a service class? - As of today

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;
}

Register class with multiple interfaces for Dependency injection in Catel

I'm using Catel 5.12.19 with an MVVM application
I have the following 2 interfaces:
public interface ICustomerSearch
{
public List<string> CustomerSearchFilterList { get; set; }
public int SelectedFilter { get; set; }
public List<ICustomer> OnFindCustomer();
}
and
public interface IService
{
}
I implement them as follow:
public class CustomerControlService: IService, ICustomerSearch
{
public IDBContext dbContext;
public List<string> CustomerSearchFilterList { get { return GetAvailableFilters(); } set {}
public int SelectedFilter { get; set; }
public CustomerControlService()
{
dbContext = new Model();
}
public CustomerControlService(IDBContext context)
{
dbContext = context;
}
public List<ICustomer> OnFindCustomer()
{
return new List<ICustomer>(dbContext.Customers);
}
private static List<string> GetAvailableFilters()
{
List<string> Result = new()
{
"Option 1",
"Option 2"
};
return Result;
}
#endregion
}
In the app.xaml.cs I register this as follow:
ServiceLocator.Default.RegisterType<IService, CustomerControlService>();
In my model I inject it in the constructor like:
public CustomerControlViewModel(IService customerControl/* dependency injection here */)
{
customersController = (CustomerControlService)ServiceLocator.Default.ResolveType<IService>();
}
But then I can't do:
public List<string> CustomerSearchFilterList = customersController.CustomerSearchFilterList;
Can I accomplish this and how?
Jeroen
IService interface is blank, therefore any code using IService can perform no actions with it.
CustomerSearchFilterList is defined as belonging to ICustomerSearch interface.
Thus for dependency injection you should be using concrete classes based upon ICustomerSearch instead of IService.
You can combine interfaces to form more complex ones e.g.
public interface IComplexInterface : ICustomerSearch, IService
{
}
Then you could inject concrete classes based upon IComplexInterface and call interface methods or properties from both ICustomerSearch and IService

Can't add generic Interface to List with same constraint

I'm struggling with generics and don't really know what I'm doing wrong.
This is my example:
public class Repository // Base-class for all repositories
{
public virtual int GetStatus()
{
return 0;
}
}
Repository is just a base class.
public class CarRepository : Repository // base-class for all car repositories
{
private object dataSource;
public override int GetStatus()
{
return dataSource.GetHashCode(); // dummy
}
public virtual int GetPrice(string carName)
{
if (carName.Equals("BMW", StringComparison.OrdinalIgnoreCase)) {
return 100;
}
return 50;
}
}
CarRepository simply provides basic methods to interact with cars.
public class HttpCarRepository : CarRepository // loads the car data from REST Api
{
private dynamic httpClient; // just as an example
public override int GetStatus()
{
return httpClient.IsConnected();
}
public override int GetPrice(string carName)
{
return httpClient.GetAsync("/rest/car/BMW").Result;
}
}
There might also be an DataBaseCarRepository that loads the data from a database. You get the point.
That's for the setup.
Now, I want to cache the results. To keep it generic, I've created this construct:
public interface ICache<TRepo> // Basic Cache Interface
where TRepo : Repository
{
TRepo Repository { get; set; }
}
public class CarCache : CarRepository, ICache<CarRepository>
{
public CarRepository Repository { get; set; }
private dynamic cache;
public CarCache(CarRepository repo)
{
this.Repository = repo;
}
public override int GetPrice(string carName)
{
if (!this.cache.Contains(carName)) {
this.cache.Add(carName, this.Repository.GetPrice(carName));
}
return cache[carName];
}
}
CarCache derives from the base class CarRepository to make it possible to override the methods. It also implements ICache<T> which provides a reference to an actual
implementation of CarRepository, such as HttpCarRepository.
Now I want to add the CarCache to a list of caches.
public class Manager
{
public List<ICache<Repository>> Caches;
}
I've used Repository as the generic type because the ICache<T> interface constraints the type to Repository.
Now the problem:
I've got a method to add a cache that looks like this
static void Add<TCache>(Repository repo)
where TCache : Repository, ICache<TCache>
{
ICache<TCache> newEntry = Activator.CreateInstance(typeof(TCache), repo) as ICache<TCache>;
Caches.Add(newEntry); // Error: Cannot convert from ICache<TCache> to ICache<Repository>
}
That confuses me. From my understanding this should work because I've added the constraint where TCache : Repository to the method, so adding an item of that type
to a list of ICache<Repository> should work. It's the same constraint.
What's the problem here?
One solution would be to make ICache<TRepo> covariant.
You would need to make TRepo Repository get-only to comply with covariant restrictions:
public interface ICache<out TRepo> where TRepo : Repository
{
TRepo Repository { get; }
}
This would work fine as long as the property is only set via your constructor:
public class CarCache : CarRepository, ICache<CarRepository>
{
public CarRepository Repository { get; }
public CarCache(CarRepository repo)
{
this.Repository = repo; // Fine to set Repository here
}
// ...
}
Or you could make the setter private to allow other methods of the implementation class to set the value:
public class CarCache : CarRepository, ICache<CarRepository>
{
public CarRepository Repository { get; private set; }
// ...
void SetRepository(CarRepository repo)
{
this.Repository = repo;
}
}

Unity with the same interface, multiple factories

So the issue, is when I declare:
[Dependency]
public AuthenticationService _authenticationServices { get; set; }
The _authenticationServices will constantly remain null. It isn't referenced, which will throw a Null Reference Exception. I'm assuming the issue stems from my Unity Configuration file:
container.RegisterType<ICrudFactory, ZNodeDataContextFactory>();
container.RegisterType<ICrudFactory, MincronDataContextFactory>();
Since they both use the same interface, but a separate concrete implementation. The implementation is as follows:
public interface ICrud : IDisposable
{
// Method's to be exposed, via general repository.
}
public interface ICrudFactory
{
ICrud Create();
}
public ZNodeDataContext : DbContext, ICrud
{
// Concrete implementation.
}
public MincronDataContext : DbContext, ICrud
{
// Concrete implementation.
}
public ZNodeDataContextFactory : ICrudFactory
{
ICrud ICrudFactory.Create()
{
return ZNodeDataContext();
}
}
public MincronDataContextFactory : ICrudFactory
{
ICrud ICrudFactory.Create()
{
return MincronDataContext();
}
}
public class AuthenticationService
{
private readonly ICrudFactory _factory;
public AuthenticationService(ICrudFactory factory)
{
_factory = factory;
}
public void Sample()
{
using(var context = _factory.Create())
context.Method(...);
}
}
I'd like to keep that structure, to avoid code duplication.
Do you want to inject ZNodeDataContextFactory into AuthenticationService ? A bit of the point with the injection is that the service should not now anything about the implementation. But if you really want a specific implementation you can create a named instance.
public class AuthenticationService
{
private readonly ICrudFactory _factory;
public AuthenticationService([Dependency("ZNodeData")] ICrudFactory factory)
{
_factory = factory;
}
}
And in your configuration:
container.RegisterType<ICrudFactory, ZNodeDataContextFactory>("ZNodeData");
container.RegisterType<ICrudFactory, MincronDataContextFactory>("MincronData");
Alternatively:
public class AuthenticationService
{
private readonly IEnumerable<ICrudFactory> _factories;
public AuthenticationService(ICrudFactory[] factories)
{
// Now you got both...
_factories = factories;
var zNodeFactory = _factories.FirstOrDefault(x => x.Factory == ZNode);
}
}
public interface ICrudFactory
{
ICrud Create();
// Something to identify the type of data. Maybe an enum?
FactoryType Factory {get;}
}
public ZNodeDataContextFactory : ICrudFactory
{
ICrud ICrudFactory.Create()
{
return ZNodeDataContext();
}
FactoryType ICrudFactory.Factory
{
{get {return FactoryType.ZNode;}
}
}
I ended up solving the issue, by creating particular containers for each generic repository.
public interface IZNodeContextFactory : ICrudFactory
{
}
public interface IMincronContextFactory : ICrudFactory
{
}
By doing it in this manner, I was able to simply do:
container.RegisterType<IZNodeContextFactory, ZNodeContextFactory>();
container.RegisterType<IMincronContextFactory, MincronContextFactory>();
This allowed the automatic dependency resolver to work, and implement since they now had unique names.

Refactor factory without violating Open Close Principle

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>

Categories