1
\$\begingroup\$

Problem: My application is built upon clean architecture. I want to create a new instance of a class in my lower layer, but the class itself resides in an upper layer. The upper layer can depend on lower layer, but the lower layer can not depend on a upper one.

Why: That's because, AuthorizationService requires new instance of requirement. These requirements sit in API layer (upper). And my resource based authorization happens in services that are situated in Application layer (lower).

My solution: I created factory pattern.

EDIT: I changed name of factory to be generic.

EDIT2: I changed factory pattern to simple factory.

THIS IS SITUATED IN SERVICE / APPLICATION LAYER

        var testFactory = _requirementFactory.Create("MemberOwnerOnlyRequirement");
        var testListReq = new List<IAuthorizationRequirement>(){testFactory}; // Testing

        var authorization = await _authorizationService.AuthorizeAsync(_currentUserService.MemberIdentity, member,  //Testing
            testListReq);

THESE INTERFACES ARE IN INTERFACES / APPLICATION LAYER

public interface IRequirementFactory
{
    IAuthorizationRequirement Create(string requirementType);
}

THESE CONCRETE CLASSES ARE IN AUTHORIZATION / API LAYER

public class RequirementFactory : IRequirementFactory
{
    public IAuthorizationRequirement Create(string requirementType)
    {
        switch (requirementType)
        {
            case "MemberOwnerOnlyRequirement":
                return new MemberOwnerOnlyRequirement();


                default:
                    return null;

        }
    }
}

public class MemberOwnerOnlyRequirement : IAuthorizationRequirement
{

}

I'm a beginner and I pursue clean code & best practices. My friend, who's a mid-level asp.net developer suggested bending the rule & create same class in Application layer, thus violating DRY.

Could you please suggest other approach / review mine?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

From the current context, it seems Requirment was meant for Provider, so instead of IRequirementFactory, and IAuthorizationRequirement it would be clearer if they were IProviderFactory and IAuthorizationProvider (or IProviderAuthorization).

The other note is requirementType instead of string it should be enum or Type (or better yet using Generics), so you can avoid human-mistake, and have a better type/value handling.

The RequirementFactory (or ProviderFactory) should handle the creation of the concrete class of the Requirement (or Provider) along with any required Requirement objects or dependencies. Think of it as a basic gateway to initialize objects with their minimum requirements.

You can either have a factory for each requirement, or you can have one Factory for all requirements (as same as the provided code). both are valid approaches., and choosing between them depends totally on the code and business logic requirements.

So, as long as the Create is inside the Factory class, it should be fine, you can also market it as static method (also another common used approach) so you can do this :

RequirementFactory.Create(typeof(MemberOwnerOnlyRequirement));

if you need a different way of Create(string requirementType); you can use Generics so you could do something like this :

public IAuthorizationRequirement Create<T>() where T : class, IAuthorizationRequirement, new()
{
    return new T();
}

the above code will restrict the creation to classes that implements IAuthorizationRequirement that have default constructors.

using that would be :

_requirementFactory.Create<MemberOwnerOnlyRequirement>();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.