-
-
Save darrencauthon/708929 to your computer and use it in GitHub Desktop.
public class CatalogContextDeterminer | |
{ | |
private XPrincipal principal; | |
public CatalogContextDeterminer(XPrincipal principal) | |
{ | |
principal = principal; | |
} | |
public Type GetCatalogContextType() | |
{ | |
if (TheUserIsNotLoggedIn()) | |
return typeof (NonMemberCatalogContext); | |
var memberType = GetTheCurrentUsersMemberType(); | |
if (ThisIsAChapterMember(memberType)) | |
return GetTheChapterPricingForThisMemberType(memberType); | |
else | |
return typeof (MemberCatalogContext); | |
} | |
// .. more here | |
} | |
public class CatalogContextRegistration : IServiceRegistration | |
{ | |
public void Register(IServiceLocator locator) | |
{ | |
locator.Register(() => | |
{ | |
var determiner = locator.Resolve<CatalogContextDeterminer>(); | |
return locator.Resolve(determiner.GetCatalogContextType()) as ICatalogContext; | |
}); | |
} | |
} |
BTW, one more point:
This class got more complex later. Client came back and wanted different pricing than chapter or member, and then had special pricing considerations based on if you were creating an account versus if you were creating an order as a guest. All of that complexity and change stayed in one place.
I know this isn't the best example of an alternative to "CanProcess()," this is just the freshest example of using this pattern in my head. But it works for other situations, too, even those where multiple classes needed to be instantiated and called.
It's really nice to be able to ask the container, "Resolve the implementation for this interface" or "Resolve all implementations of this interface" and know that whatever you get back is relevant to your situation.
The catalog you get (i.e. the pricing, the products that are available, etc.) depends on whether you are signed in and your type. Then whenever someone requests that catalog out of the container, this logic is used to determine which one you get.
What this also does is make each of the catalog classes very simple. NonMemberCatalogContext only contains the logic necessary to get the products & prices for non-members, MemberCatalogContext for members, and so on. This is an alternative to having some sort of "CanProcess" method where the classes are also aware of the context in which they should be used (which, under SRP, they shouldn't have to handle).
It also makes testing as simple as:
Given I am not logged in
When I request product information
Then I should get the non-member pricing
// ^^ which will test that NonMemberCatalogContext is returned
Given I am logged in
And my member type is 'APPLE'
When I request product information
Then I should get the Apple pricing
Given I am logged in
And my member type is 'ORANGE'
When I request product information
Then I should get the Member pricing
// you get the point....