Architecture problem: use of dependency injection resulting in rubbish API - c#

I'm tring to create a class which does all sorts of low-level database-related actions but presents a really simple interface to the UI layer.
This class represents a bunch of data all within a particular aggregate root, retrieved by a single ID int.
The constructor takes four parameters:
public AssetRegister(int caseNumber, ILawbaseAssetRepository lawbaseAssetRepository, IAssetChecklistKctcPartRepository assetChecklistKctcPartRepository, User user)
{
_caseNumber = caseNumber;
_lawbaseAssetRepository = lawbaseAssetRepository;
_assetChecklistKctcPartRepository = assetChecklistKctcPartRepository;
_user = user;
LoadChecklists();
}
The UI layer accesses this class through the interface IAssetRegister. Castle Windsor can supply the ILawbaseAssetRepository and IAssetChecklistKctcPartRepository parameters itself, but the UI code needs to supply the other two using an anonymous type like this:
int caseNumber = 1000;
User user = GetUserFromPage();
IAssetRegister assetRegister = Moose.Application.WindsorContainer.Resolve<IAssetRegister>(new { caseNumber, user});
From the API design point of view, this is rubbish. The UI layer developer has no way of knowing that the IAssetRegister requires an integer and a User. They need to know about the implementation of the class in order to use it.
I know I must have some kind of design issue here. Can anyone give me some pointers?

Try separating the message from the behavior. Make a class that holds the data for the operation, and create a different class that contains the business logic for that operation. For instance, create this command:
public class RegisterAssetCommand
{
[Required]
public int CaseNumber { get; set; }
[Required]
public User Operator { get; set; }
}
Now define an interface for handling business commands:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
Your presentation code will now look like this:
var command = new RegisterAssetCommand
{
CaseNumber = 1000,
Operator = GetUserFromPage(),
};
var commandHandler = WindsorContainer
.Resolve<ICommandHandler<RegisterAssetCommand>);
commandHandler.Handle(command);
Note: If possible, move the responsibility of getting a commandHandler out of the presentation class and inject it into the constructor of that class (constructor injection again).
No you can create an implementation of the ICommandHandler<RegisterAssetCommand> like this:
public class RegisterAssetCommandHandler
: ICommandHandler<RegisterAssetCommand>
{
private ILawbaseAssetRepository lawbaseAssetRepository;
private IAssetChecklistKctcPartRepository assetRepository;
public RegisterAssetCommandHandler(
ILawbaseAssetRepository lawbaseAssetRepository,
IAssetChecklistKctcPartRepository assetRepository)
{
this.lawbaseAssetRepository = lawbaseAssetRepository;
this.assetRepository = assetRepository;
}
public void Handle(RegisterAssetCommand command)
{
// Optionally validate the command
// Execute the command
}
}
Optionally, you could perhaps even leave the User out of the RegisterAssetCommand by injecting a IUserProvider in the RegisterAssetCommandHandler. The IUserProvider interface could have an GetUserForCurrentContext that the handler can call.
I hope this makes sense.

As Morten points out, move the non injectable dependecies from the constructor call to the method(s) that actually need to use it,
If you have constructor paramters that can't (or are difficult to) be injected you won't be able to autmatically inject IAssetRegister into any class that needs it either.
You could always, of course, create a IUserProvider interface with a concrete implementation along these lines:
public class UserProvider : IUserProvider
{
// interface method
public User GetUser()
{
// you obviously don't want a page dependency here but ok...
return GetUserFromPage();
}
}
Thus creating another injectable dependency where there was none. Now you eliminate the need to pass a user to every method that might need it.

Related

c# how to initialize or set a default constructor value to a injected dependency from class

I have a class that uses dependency injection:
public class MainClass: IDisposable
{
IUtilityRepository _utilityRepo = null;
public MainClass()
{
}
public MainClass(IUtilityRepository utilityRepo)
{
_utilityRepo = utilityRepo;
}
}
Then my UtilityRepository class has:
public class UtilityRepository : IUtilityRepository
{
private int _userId;
private int _sessionId;
// maybe have here some constructor where i can get some values from MainClass
public UtilityRepository ()
{
// here set the private properties from the MainClass when the dependency is intialized from MainClass
}
public List<string> MethodTestOne(string tempFolder)
{
// here I want to
}
public List<string> MethodTestTwo(string tempFolder)
{
}
}
What I want to do is to pass from MainClass two properties to UtilityRepository class so any method within UtilityRepository can use those values globaly in the class without the need of passing the values to every method in a independant way.
Any clue?
TL;DR: We should inject dependencies into the classes that need them. Classes shouldn't be responsible for providing dependencies to their dependencies.
If MainClass receives userId and sessionId from somewhere, how does it receive them? Presumably they are injected into MainClass, or something that provides them is injected.
If MainClass receives them via injection, UtilityRepository can receive them the same way. If MainClass doesn't receive them via injection, configure your container to inject them into UtilityRepository anyway. That could look like this:
public interface IContext // not the greatest name
{
string UserId { get; }
string SessionId { get; }
}
or
public interface IContextAccessor
{
// where Context is an object containing the values you need.
Context GetContext();
}
Then you configure the container provide a runtime implementation of IContextAccessor that retrieves the values from the current request. Inject IContextAccessor into UtilityRepository.
public class UtilityRepository : IUtilityRepository
{
private readonly IContextAccessor _contextAccessor;
public UtilityRepository(IContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
}
If MainClass doesn't need those values (it was only receiving them so it could pass them to something else) then it shouldn't receive them. If MainClass does need them, the fact that UtilityRepository also needs them is coincidental. (You can inject IContextAccessor into MainClass too.) There's no reason why MainClass needs to be responsible for passing them to UtilityRepository.
MainClass depends on an abstraction - IUtilityRepository. It does not and should not know what the concrete implementation of that interface depends on. It shouldn't know anything at all that isn't in that interface. As soon as it does, it no longer "depends" on the interface. It's coupled to the implementation.
That's one of the primary benefits of using an IoC container. Classes get their dependencies from the container, not from each other. Depending on abstractions means that classes don't know how those abstractions are implemented. That in turn means that classes don't know about the the dependencies of their dependencies.
To illustrate: A lamp depends on an abstraction - a power outlet that gets its power from somewhere. It could a be a power grid, a solar panel, a generator, a bicycle, or anything else.
Whatever the implementation of the power source is, it probably has dependencies of its own. A generator needs gasoline. A power grid needs a power plant.
Those dependencies probably have dependencies of their own. A power plant needs someone to shovel coal.
The lamp shouldn't know anything about those dependencies. If using a lamp means:
Plug in the lamp
Turn on the lamp
Put gas in the generator
Then we're no longer depending on an abstraction. We're depending on a generator. It doesn't matter if we declare it as an interface and call it IPowerSupply. The only implementation it can work with is a generator.
The same goes for the power grid. It depends on a power source. That power source might require coal, generators, etc. But what happens if we make the power grid responsible for starting the generator, and then later we want to replace the generator with a massive solar panel array? How will the power grid start the generator when there is no generator?
That's why every class should know as little as possible about its dependencies. If it knows something, it's coupled to that detail. The whole point of Dependency Inversion (depending on abstractions) is to prevent or minimize coupling so that changing one implementation detail doesn't have a ripple effect that forces us to change other things that shouldn't have to change.
IoC containers make it super easy for us to accomplish that. Every class says what it needs by requiring it in the constructor, and the container injects it. If the thing injected has its own dependencies, the container takes care of that too. All of our classes get constructed independently without knowing anything about each other.
Basically, passing parameters to constructor of an implementation introduces coupling which is the opposite of the dependency injection principle.
However, if you define a requirement that every implementation must receive the two parameters userId and sessionId in constructor, the decoupling is preserved, since all implementations adhere to this convention.
To enable such a scenario, MainClass must receive IKernel parameter, rather than IUtilityRepository:
public class MainClass
{
private readonly IUtilityRepository _utilityRepo = null;
public MainClass()
{
}
public MainClass(IKernel kernel)
{
var userId = new Ninject.Parameters.ConstructorArgument("userId", 123);
var sessionId = new Ninject.Parameters.ConstructorArgument("sessionId", 456);
_utilityRepo = kernel.Get<IUtilityRepository>(userId, sessionId);
}
}
In this way UtilityRepository will be able to receive the two parameters in the constructor:
public class UtilityRepository : IUtilityRepository
{
private readonly int _userId;
private readonly int _sessionId;
// maybe have here some constructor where i can get some values from MainClass
public UtilityRepository (int userId, int sessionId)
{
_userId = userId;
_sessionId = sessionId;
}
public List<string> MethodTestOne(string tempFolder)
{
// do something...
}
public List<string> MethodTestTwo(string tempFolder)
{
// do something...
}
}
Note that in such a case, the registration of UtilityRepository must be transient, so that a new instance is created every time it's requested with the specific parameter values:
kernel.Bind<IUtilityRepository>().To<UtilityRepository>().InTransientScope();
One downside of this solution is that MainClass doesn't use constructor parameters any longer in order to explicitly declare its dependencies. The code is now less self-documenting.

C# Interfaces & Dependency Injection

I am trying to understand a little more about interface injection and how it all hangs together.
My system has different types of users. Each user will see a different set of menu on the home page. Rather than having a big switch statement checking the type of user & load menu accordingly, I created a "User" base class and the derived classes implement the IMenu interface. But on Page_Load(), I still need to know the type of User to create before I can call the LoadMenu() method. My question is, how can I get away from hard-coding the instantiation of a type of User object? Or even when I retrieve the data from DB and create a type of User object, I still need to check the type of user and use switch. Is there a way to get away from that?
Below is my code
//base class
Public class User {
private string _Username;
Private string _Name;
}
Public Interface IMenu {
void LoadMenu();
}
Public class Manager : User, IMenu {
public override void LoadMenu(){
//loads manager's menu
}
}
public class Employee: User, IMenu {
public override void LoadMenu(){
//loads employee's menu
}
}
protected void Page_Load() {
//Retrieve user details from database
//Instantiate an object of derived `User` type.
//Call `LoadMenu()` method.
}
If you want to use dependency injection to load different types that adhere to a common interface, you should look into typed factories (at least that's how it is called in castle-windsor - the same concept should be found in other frameworks)
The principle is the following: you have an interface which returns the common interface you're interested in
public interface IUserFactory {
IUser GetUser(string userType);
}
Then you register all your types deriving from the common interface you want to resolve, with a discriminating information; it can be the type of the class, or some other information.
Finally you inform the factory about the link between the types that have been registered and the discriminating information; for example if we had used the class type as the name of a component in a windsor factory, then we could tell the factory that a request for IUser should be resolved by using the parameter we pass it as the component name. In Windsor this can done by inheriting from DefaultTypedFactoryComponentSelector
public class CustomTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
if(method.Name == "GetUser" && arguments.Length == 1 && arguments[0] is string)
{
return (string)arguments[0];
}
return base.GetComponentName(method, arguments);
}
}
You would then get something like
var dbUser = DB.LoadUser(1234);
IUser user = IUserFactory.GetUser(dbUser.Type);
user.LoadMenu();
As a matter of style, I'd recommend not giving a user the responsibility to load the menu; instead you would perhaps be in a better place if the menu was loaded by passing it the user, or even best an interface that describes authorized actions. This way you can load a menu for a user, but the menu is not limited by it and be loaded for machines, groups, etc... This is architecture country, so I won't stray any further but the comments under your question are good pointers :)
I'm a little bewildered with your concept that avoiding switch statements is equivalent to dependency injection. Sooner or later you need to place the logic of what to do with your application's menu depending on your current user.
Dependency injection is about decoupling as much as possible your arquitecture from the logic of that decision, not avoiding it. If done right, even if in the future that logic changes you don't need to rewrite half your code.
I don't know if I would do it the way you are planning, but based on your approach, I'd do something similar to the following (thought up really fast so its bound to have holes in it, but you should get the idea):
public enum UserAccessLevel
{
None,
Employee,
Manager
}
public interface IUser
{
string Name { get; }
string UserName { get; }
UserAccessLevel AccessLevel { get; }
}
public interface IMenuLoader
{
void LoadMenu()
}
public class MenuLoaderFactory()
{
public IMenuLoader GetMenuLoader(UserAccesLevel accesLevel)
{
IMenuLoader menuLoader = null;
switch (accesLevel)
{
case UserAccessLevel.Employee
menuLoader = new EmployeeMenuLoader();
break;
case UserAccessLevel.Manager
menuLoader = new ManagerMenuLoader();
}
return menuLoader ;
}
}
public sealed class EmployeeMenuLoader: IMenuLoader {...}
public sealed class ManagerMenuLoader: IMenuLoader {...}
Now in you main page you should only hold references to IUser, IMenuLoader. If in a few months, you decide to add a new access level, all the plumbing is still valid. You'd only need to create the new MenuLoader class and update the logic in the MenuLoaderFactory and UserLevelAccess Enum (on second though I'd probably get rid of this enum) to take into account the new access and your set.

Get instance of a class using generics

I'm working on a game that uses MVCS and has, so far, clearly separated the business logic from the view.
However, I've been having trouble with one particular piece of the puzzle.
In the game we have command classes (IPlayerCommand) that execute a specific business logic. Each command class returns a result class (PlayerCommandResult). For each PlayerCommand we have a respected visual command class (IVisualPlayerCommand) that takes the PlayerCommandResult and updates the view accordingly.
I'd like the IVisualPlayerCommand to use specific classes that inherit PlayerCommandResult in order to get the information it needs (as opposed to using object). I'd also like to make it compile-time safe (as opposed to casting it before using it). For these two reasons I made the classes use generics.
Here are the declaration of the classes:
public class PlayerCommandResult
{}
public interface IPlayerCommand<T> where T : PlayerCommandResult
{
T Execute(GameWorld world);
}
public interface IVisualPlayerComamnd<T> where T : PlayerCommandResult
{
void Play(T commandResult);
}
Here is the Move Unit command as an example:
public class MoveUnitPlayerCommand : IPlayerCommand<MoveUnitPlayerCommandResult>
{
private Unit unitToMove;
public MoveUnitPlayerCommand(Unit unit)
{
this.unitToMove = unit;
}
public MoveUnitPlayerCommandResult Execute(GameWorld world)
{
MoveUnitPlayerCommand result = new MoveUnitPlayerCommand();
// Do some changes to the world and store any information needed to the result
return result;
}
}
public class MoveUnitVisualPlayerCommand : IVisualPlayerCommand<MoveUnitPlayerCommandResult>
{
void Play(MoveUnitPlayerCommandResult commandResult)
{
// Do something visual
}
}
public class MoveUnitPlayerCommandResult : PlayerCommandResult
{
public Unit TargetUnit { get; private set; }
public Path MovePath { get; private set; }
}
So far, so good. However, I'm having a really hard time tying a IPlayerCommand to a IVisualPlayerCommand because of the use of generics:
public class CommandExecutorService
{
public void ExecuteCommand<T>(IPlayerCommand<T> command) where T : PlayerCommandResult
{
T result = command.Execute(world);
IVisualPlayerCommand<T> visualCommand = GetVisualPlayerCommand(command);
visualCommand.Play(result);
}
public IVisualPlayerCommand<T> GetVisualPlayerCommand<T>(IPlayerCommand<T> command) where T : PlayerCommandResult
{
// ?!?!?!?!?!??!?!?!??!?!
}
}
I have a feeling that what I'm trying to do is not even possible because of the way generics work in C# (as opposed to Java where I could say IVisualPlayerCommand<?>).
Could you help me figure out a way?
Any feedback for the design is welcome.
P.S. Sorry if the title doesn't reflect the question. I wasn't sure how to boil down the question in one line.
P.P.S. Which is why I also don't know if this question has been asked and answered before.
You two command classes, are served as service. To me, for this case, I would use the service locator pattern. As how to implement this pattern, you can check this link
The drawback of using template, is that, if something changes, you have to compiled it again.
Here's link which provides an example of the service locator pattern.
So for you code, you want find the corresponding instance of IVisualPlayerCommand to IPlayerCommand, so the concrete service can inherit from both interface, which it actually implements the IVisualPlayerCommand interface, while the IPlayerCommand just severs as a tag.
so the code will like this:
class MoveUnitVisualPlayerCommand: IVisualPlayerCommand, IPlayerCommand {}
services = new Dictionary<object, object>();
this.services.Add(typeof(IPlayerCommand ), new MoveUnitVisualPlayerCommand());
as how to get the service, you can refer the example.
Hope this helps.

should new behavior be introduced via composition or some other means?

I chose to expose some new behavior using composition vs. injecting a new object into my consumers code OR making the consumer provide their own implementation of this new behavior. Did I make a bad design decision?
I had new requirements that said that I needed to implement some special behavior in only certain circumstances. I chose to define a new interface, implement the new interface in a concrete class that was solely responsible for carrying out the behavior. Finally, in the concrete class that the consumer has a reference to, I implemented the new interface and delegate down to the class that does the work.
Here are the assumptions that I was working with...
I haven an interface, named IFileManager that allows implementors to manage various types of files
I have a factory that returns a concrete implementation of IFileManager
I have 3 implementations of IFileManager, these are (LocalFileManager, DfsFileManager, CloudFileManager)
I have a new requirements that says that I need to manage permissions for only the files being managed by the CloudFileManager, so the behavior for managing permissions is unique to the CloudFileManager
Here is the test that led me to the code that I wrote...
[TestFixture]
public class UserFilesRepositoryTest
{
public interface ITestDouble : IFileManager, IAclManager { }
[Test]
public void CreateResume_AddsPermission()
{
factory.Stub(it => it.GetManager("cloudManager")).Return(testDouble);
repository.CreateResume();
testDouble.AssertWasCalled(it => it.AddPermission());
}
[SetUp]
public void Setup()
{
testDouble = MockRepository.GenerateStub<ITestDouble>();
factory = MockRepository.GenerateStub<IFileManagerFactory>();
repository = new UserFileRepository(factory);
}
private IFileManagerFactory factory;
private UserFileRepository repository;
private ITestDouble testDouble;
}
Here is the shell of my design (this is just the basic outline not the whole shibang)...
public class UserFileRepository
{
// this is the consumer of my code...
public void CreateResume()
{
var fileManager = factory.GetManager("cloudManager");
fileManager.AddFile();
// some would argue that I should inject a concrete implementation
// of IAclManager into the repository, I am not sure that I agree...
var permissionManager = fileManager as IAclManager;
if (permissionManager != null)
permissionManager.AddPermission();
else
throw new InvalidOperationException();
}
public UserFileRepository(IFileManagerFactory factory)
{
this.factory = factory;
}
private IFileManagerFactory factory;
}
public interface IFileManagerFactory
{
IFileManager GetManager(string managerName);
}
public class FileManagerFactory : IFileManagerFactory
{
public IFileManager GetManager(string managerName)
{
IFileManager fileManager = null;
switch (managerName) {
case "cloudManager":
fileManager = new CloudFileManager();
break;
// other managers would be created here...
}
return fileManager;
}
}
public interface IFileManager
{
void AddFile();
void DeleteFile();
}
public interface IAclManager
{
void AddPermission();
void RemovePermission();
}
/// <summary>
/// this class has "special" behavior
/// </summary>
public class CloudFileManager : IFileManager, IAclManager
{
public void AddFile() {
// implementation elided...
}
public void DeleteFile(){
// implementation elided...
}
public void AddPermission(){
// delegates to the real implementation
aclManager.AddPermission();
}
public void RemovePermission() {
// delegates to the real implementation
aclManager.RemovePermission();
}
public CloudFileManager(){
aclManager = new CloudAclManager();
}
private IAclManager aclManager;
}
public class LocalFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
public class DfsFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
/// <summary>
/// this class exists to manage permissions
/// for files in the cloud...
/// </summary>
public class CloudAclManager : IAclManager
{
public void AddPermission() {
// real implementation elided...
}
public void RemovePermission() {
// real implementation elided...
}
}
Your approach to add your new behavior only saved you an initialization in the grand scheme of things because you to implemented CloudAclManager as separate from CloudFileManager anyways. I disagree with some things with how this integrates with your existing design (which isn't bad)...
What's Wrong With This?
You separated your file managers and made use of IFileManager, but you didn't do the same with IAclManager. While you have a factory to create various file managers, you automatically made CloudAclManager the IAclManager of CloudFileManager. So then, what's the point of having IAclManager?
To make matters worse, you
initialize a new CloudAclManager
inside of CloudFileManager every time you try to get its ACL
manager - you just gave factory
responsibilities to your
CloudFileManager.
You have CloudFileManager implement IAclManager on top of having it as a property. You just moved the rule that permissions are unique to CloudFileManager into your model layer rather than your business rule layer. This also results in supporting the unnecessary
potential of circular referencing between self and property.
Even if you wanted
CloudFileManager to delegate the
permission functionality to
CloudAclManager, why mislead other
classes into thinking that
CloudFileManager handles its own
permission sets? You just made your
model class look like a facade.
Ok, So What Should I Do Instead?
First, you named your class CloudFileManager, and rightly so because its only responsibility is to manage files for a cloud. Now that permission sets must also be managed for a cloud, is it really right for a CloudFileManager to take on these new responsibilities? The answer is no.
This is not to say that you can't have code to manage files and code to manage permissions in the same class. However, it would then make more sense for the class to be named something more general like CloudFileSystemManager as its responsibilities would not be limited to just files or permissions.
Unfortunately, if you rename your class it would have a negative effect on those currently using your class. So how about still using composition, but not changing CloudFileManager?
My suggestion would be to do the following:
1. Keep your IAclManager and create IFileSystemManager
public interface IFileSystemManager {
public IAclManager AclManager { get; }
public IFileManager FileManager { get; }
}
or
public interface IFileSystemManager : IAclManager, IFileManager {
}
2. Create CloudFileSystemManager
public class CloudFileSystemManager : IFileSystemManager {
// implement IFileSystemManager
//
// How each manager is set is up to you (i.e IoC, DI, simple setters,
// constructor parameter, etc.).
//
// Either way you can just delegate to the actual IAclManager/IFileManager
// implementations.
}
Why?
This will allow you to use your new behavior with minimal impact to your current code base / functionality without affecting those who are using your original code. File management and permission management can also coincide (i.e. check permissions before attempting an actual file action). It's also extensible if you need any other permission set manager or any other type of managers for that matter.
EDIT - Including asker's clarification questions
If I create IFileSystemManager : IFileManager, IAclManager, would the repository still use the FileManagerFactory and return an instance of CloudFileSystemManager?
No, a FileManagerFactory should not return a FileSystemManager. Your shell would have to update to use the new interfaces/classes. Perhaps something like the following:
private IAclManagerFactory m_aclMgrFactory;
private IFileManagerFactory m_fileMgrFactory;
public UserFileRepository(IAclManagerFactory aclMgrFactory, IFileManagerFactory fileMgrFactory) {
this.m_aclMgrFactory = aclMgrFactory;
this.m_fileMgrFactory = fileMgrFactory;
}
public void CreateResume() {
// I understand that the determination of "cloudManager"
// is non-trivial, but that part doesn't change. For
// your example, say environment = "cloudManager"
var environment = GetEnvMgr( ... );
var fileManager = m_fileMgrFactory.GetManager(environment);
fileManager.AddFile();
// do permission stuff - see below
}
As for invoking permission stuff to be done, you have a couple options:
// can use another way of determining that a "cloud" environment
// requires permission stuff to be done
if(environment == "cloudManager") {
var permissionManager = m_aclMgrFactory.GetManager(environment);
permissionManager.AddPermission();
}
or
// assumes that if no factory exists for the environment that
// no permission stuff needs to be done
var permissionManager = m_aclMgrFactory.GetManager(environment);
if (permissionManager != null) {
permissionManager.AddPermission();
}
I think that composition is exactly the right means to to this kind of trick. But I think you should keep it more simple (KISS) and just make an IAclManager property in the IFileManager and set it to null by default and set the SecurityManager implementation for the cloud service there.
This has different upsides:
You can check if permissions need to be checked by nullchecking the securityManager property. This way, if there doesn't need to be permissionsManaging done (as with localfile system), you don't have exceptions popping up. Like this:
if (fileManager.permissionsManager != null)
fileManager.permissionsManager.addPermission();
When you then carry out the task (to add or delete a file), you can check again if there's a permissionsManager and if the permission is given, if not throw exception (as you'll want to throw the exception when a permission to do an action is missing, not if a permission is missing in general if you're not going to add or delete files).
You can later on implement more IAclManagers for the other IFileManagers when your customer changes the requirements next time the same way as you would now.
Oh, and then you won't have such a confusing hierarchy when somebody else looks at the code ;-)
In general it looks good, but I do have a few suggestions. It seems that your CreateResume() method implementation demands a IFileManager that is also an IAclManager (or else it throws an exception).
If that is the case, you may want to consider adding an overload to your GetManager() method in which you can specify the interface that you require, and the factory can have the code that throws an exception if it doesn't find the right file manager. To accompolish this you can add another interface that is empty but implements both IAclManager and IFileManager:
public interface IAclFileManager : IFileManager, IAclManager {}
And then add the following method to the factory:
public T GetManager<T>(string name){ /* implementation */}
GetManager will throw an exception if the manager with the name given doesn't implement T (you can also check if it derives from or is of type T also).
All that being said, if AddPermissions doesn't take any parameters (not sure if you just did this for the post), why not just call AddPermissions() from CloudFileManager.AddFile() method and have it completely encapsulated from the user (removing the need for the new IAclManager interface)?
In any event, doesn't seem like a good idea to call AddFile in the CreateResume() method and only then throw the exception (since you now you have now created a file without the correct permissions which could be a security issue and also the consumer got an exception so he may assume that AddFile didn't succeed, as opposed to AddPermission).
Good luck!

Factory class knows too much

UPDATED I've updated the example to better illustrate my problem. I realised it was missing one specific point - namely the fact that the CreateLabel() method always takes a label type so the factory can decide what type of label to create. Thing is, it might need to obtain more or less information depending on what type of label it wants to return.
I have a factory class that returns objects representing labels to be sent to a printer.
The factory class looks like this:
public class LargeLabel : ILabel
{
public string TrackingReference { get; private set; }
public LargeLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class SmallLabel : ILabel
{
public string TrackingReference { get; private set; }
public SmallLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
}
}
}
Say that I create a new label type, called CustomLabel. I want to return this from the factory, but it needs some additional data:
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
CustomText = customText;
}
}
This means my factory method has to change:
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference, string customText)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
case LabelType.Custom:
return new CustomLabel(trackingReference, customText);
}
}
}
I don't like this because the factory now needs to cater for the lowest common denominator, but at the same time the CustomLabel class needs to get a custom text value. I could provide the additional factory method as an override, but I want to enforce the fact that the CustomLabel needs the value, otherwise it'll only ever be given empty strings.
What is the correct way to implement this scenario?
Well, how do you want to call the factory method?
Concentrate on how you want to be able to use your API, and the implementation will usually make itself fairly clear. This is made even easier if you write the desired results of your API as unit tests.
An overload may well be the right thing to do here, but it really depends on how you want to use the factory.
How about just using the Factory method to decide what label you need?
public class LabelFactory {
public ILabel CreateLabel(string trackingReference, string customText) {
return new CustomLabel(trackingReference, customText);
}
public ILabel CreateLabel(String trackingReference) {
return new BasicLabel(trackingReference);
}
}
Your factory still needs to know about each type (although with an interface you can implement dynamic loading) but there is very little that the client needs to know - according to what data is provided, the factory generates the correct implementation.
This is a simplistic solution to the simple problem you described. I assume the question is an oversimplification of a more complex problem but without knowing what your real problem is, I'd rather not design an over complex solution.
This is probably an indication that a factory pattern isn't the best for you. If you do either need or wish to stick with it, though, I would suggest creating initialization classes/structs that can be passed into the factory, rather than the string. Whether you want to do it with various subclasses of a basic information class (basically creating an initialization class hierarchy that mimics that of your label classes) or one class that contains all of the information is up to you.
You should try to use a configuration class and pass an instance of that to the factory. The configuration classes would build a hierarchy, where a special configuration class would exist for each result you expect from the factory. Each configuration class captures the specific properties of the factory result.
For the example you've given I'd write a BasicLabelConfiguration and a CustomLabelConfiguration derived from it. The BasicLabelConfiguration captures the tracking reference, while the CustomLabelConfiguration captures the custom text.
Finally the factory makes a decision based on the type of the passed configuration object.
Here's an example of the code:
public class BasicLabelConfiguration
{
public BasicLabelConfiguration()
{
}
public string TrackingReference { get; set; }
}
public class CustomLabelConfiguration : BasicLabelConfiguration
{
public CustomLabelConfiguration()
{
}
public string CustomText { get; set; }
}
public class LabelFactory
{
public ILabel CreateLabel(BasicLabelConfiguration configuration)
{
// Possibly make decision from configuration
CustomLabelConfiguration clc = configuration as CustomLabelConfiguration;
if (clc != null)
{
return new CustomLabel(clc.TrackingReference, clc.CustomText);
}
else
{
return new BasicLabel(configuration.TrackingReference);
}
}
}
Finally you'd use the factory like this:
// Create basic label
ILabel label = factory.CreateLabel(new BasicLabelConfiguration
{
TrackingReference = "the reference"
});
or
// Create basic label
ILabel label = factory.CreateLabel(new CustomLabelConfiguration
{
TrackingReference = "the reference",
CustomText = "The custom text"
});
Without further information it's pretty hard to give any advice, but assuming that the factory pattern is what you actually need you could try the following approach:
Pack the needed arguments in some kind of property map (e.g. map of string to string) and pass that as an argument to the factory's create method. Use well-known tags as keys in the map, allowing the specialized factories to extract and interpret the mapped values to their own liking.
This will at least allow you to maintain a single factory interface for the time being, and postpone dealing with architectural issues if (or when) you notice that the factory pattern isn't the correct one here.
(Oh, and if you really want to use the factory pattern here I strongly suggest you make it pluggable to avoid having to modify the factory for each new label type).
You are trying to force the pattern into a scenario in which it does not fit. I would suggest giving up on that particular pattern and focus instead of making the simplest solution possible.
I think in this case I would just have one class, Label, that has a text field for custom text that is normally null/empty but which one can set if the label needs to be custom. It is simple, self-explanatory and will not give your maintenance programmers any nightmares.
public class Label
{
public Label(string trackingReference) : this(trackingReference, string.Empty)
{
}
public Label(string trackingReference, string customText)
{
CustomText = customText;
}
public string CustomText ( get; private set; }
public bool IsCustom
{
get
{
return !string.IsNullOrEmpty(CustomText);
}
}
}
ANSWER UPDATED FOLLOWING UPDATE OF THE QUESTION - SEE BELOW
I still think you're right to be using the Factory pattern, and correct in overloading the CreateLabel method; but I think in passing the LabelType to the CreateLabel method, you're missing the point of using the Factory pattern.
Key point: the entire purpose of the Factory pattern is to encapsulate the logic which chooses which concrete subclass to instantiate and return. The calling code should not be telling the Factory which type to instantiate. The benefit is that the code which calls the Factory is therefore shielded from changes to that logic in the future, and also from the addition of new concrete subclasses to the factory. All your calling code need depend on is the Factory, and the Interface type returned from CreateLabel.
The logic in your code at the point where you call the Factory must currently look something like this pseudocode...
// Need to create a label now
ILabel label;
if(we need to create a small label)
{
label = factory.CreateLabel(LabelType.SmallLabel, "ref1");
}
else if(we need to create a large label)
{
label = factory.CreateLabel(LabelType.LargeLabel, "ref1");
}
else if(we need to create a custom label)
{
label = factory.CreateLabel(LabelType.CustomLabel, "ref1", "Custom text")
}
...so you're explicitly telling the Factory what to create. This is bad, because every time a new label type is added to the system, you'll need to...
Change the factory code to deal with the new LabelType value
Go and add a new else-if to everywhere that the factory's called
However, if you move the logic that chooses the LabelType value into your factory, you avoid this. The logic is encapsulated in the factory along with everything else. If a new type of label is added to your system, you only need to change the Factory. All existing code calling the Factory remains the same, no breaking changes.
What is the piece of data that your current calling code uses to decide whether a big label or small label is needed? That piece of data should be passed to the factory's CreateLabel() methods.
Your Factory and label classes could look like this...
// Unchanged
public class BasicLabel: ILabel
{
public LabelSize Size {get; private set}
public string TrackingReference { get; private set; }
public SmallLabel(LabelSize size, string trackingReference)
{
Size = size;
TrackingReference = trackingReference;
}
}
// ADDED THE NULL OR EMPTY CHECK
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
if(customText.IsNullOrEmpty()){
throw new SomeException();
}
CustomText = customText;
}
}
public class LabelFactory
{
public ILabel CreateLabel(string trackingReference, LabelSize labelSize)
{
return new BasicLabel(labelSize, trackingReference);
}
public ILabel CreateLabel(string trackingReference, string customText)
{
return new CustomLabel(trackingReference, customText);
}
}
I hope this is helpful.
From reading your question it sounds like your UI collects the information and then uses the factory to create the appropriate label. We use a different approach in the CAD/CAM application I develop.
During startup my applications uses the factory method to create a master list of labels.
Some of my labels have initialization parameters because they are variants of each other. For example we have three type of flat part labels. While others have parameters that are user defined or not known at setup.
In the first case the initialization is handled within the factory method. So I create three instances of FlatPartLabel passing in the needed parameters.
In the second case Label interface has a configure option. This is called by the label printer dialog to populate a setup panel. In your case this is where the tracking reference and CustomText would be passed in.
My label interface also returns a unique ID for each Label type. If I had a specific command to deal with that type of label then I would traverse the list of labels in my application find which one matches the ID, cast it to the specific type of label, and then configure it. We do this when user want to print one label only for a specific flat part.
Doing this means you can be arbitrary complex in the parameters your labels need and not burden your Factory with unessential parameters.

Categories