开发者

Avoid circular references with services and DI

I have a service assembly with multiple service classes. Each class groups a set of related service methods. These services are instantiated using IoC and constructor injectors.

If I have two service classes that may, at times, need to call methods in the other, what is the best way to handle these in order to avoid circular references?

For example, assume the two service methods from two different service classes (not necessarily the most practical example, but for simplicity's sake):

public class UserService
{
    public void RegisterUser(User user)
    {
        // Do a bunch of stuff needed to register a user

        // Now call out to permission service to set up basic permissions
        _permissionService.SetUpBasicPermissions(user);
    }
}

public class PermissionService
{
    public void GrantPermission(User user, int PermissionId)
    {
        // Add user permission to database

        // Now call out to user se开发者_如何学编程rvice to do some other stuff on the user
        _userService.TakeActionsOnUserAccount(user);
    }
}

Here are the options I can see:

  1. Considering functionality needs to be shared between the two, this is a sign the service classes should be merged into one class. If this is the case, though, might I ultimately end up with one giant service class? What determines how they should be split up?

  2. Don't combine both classes, but move methods that share logic into their own service class (leaving the user and permission specific logic in their individual classes). If this is the case, I may end up with several of these shared services, and I'm thinking that's not a good thing.

  3. Any actions needed from one service into another should be moved to the calling code. This seems problematic to me, since I would be removing potentially dependent logic, and making it another layer's concern. In other words, where ever I call _userService.RegisterUser(), I will now always have to call _permissionService.SetUpBasicPermissions() immediately following every call.

  4. Allow one service to call the other, but not both. If this is the case, which one do I choose? What do I do w/ the logic for the one that can't call the other?

  5. Use delegates to inject dependent service methods into the called service methods. Bleh, this sounds ugly.

Those are the ones I can think of, but I'm sure there are some I'm overlooking.

Thoughts?

Thanks in advance.


  1. The SRP principles states that every object should have a single responsibility so it's not ok to merge the classes.
  2. That's way inheritance way invented, use an abstract classes for common code and specialize after (don't use references)
  3. Dependency logic is bad, RegisterUser should do only that Register, not give Permissions. It's ok to move the dependency to the calling layer.
  4. Do this only if you must, it should be a bit clear after you make the abstrat class. Try object composition though.
  5. It's called a container, and you should understand it better after you read: http://www.potstuck.com/2009/01/08/php-dependency-injection

Regarding the circular references, the OOP principles only say to avoid circular references between abstract and concrete classes (Hollywood Principle) which is not the case. It's ok to use them like you do.

However, you are using very well Dependency Injection so you can extract the SetUpBasicPermissions and put it outside the class.

objUser = new User();
objUserService.RegisterUser(objUser);
objPermissionService.SetUpBasicPermissions(objUser);


If you want to have both services reference each other you will need to use Property Injection (or method) rather than constructor so that they can be fully created before it gets passed onto the other class.

As far as the design of having one service call the other in some cases this is ok provided that the logical flow of operations make sense. Although possible trying to keep it to a minimum is a better design as increasing dependencies increases coupling and having to map the behavior more closely in unit tests.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜