General, reusable solutions to common problemsNot a complete, finished solutionA template, recipe, or approach to solving certain problemsEach has a specific name, so we can discuss common elements of design using a common vocabulary
Learning anything – a musical chord, a martial arts technique, etc.Zero: You used a what? Never heard of it.Awakening:Wow, I just learned how XYZ pattern can improve my design. I’m not really sure where it would work in my code, but I’m definitely looking.Overzealous:I totally “get” the XYZ pattern; I’m adding it everywhere I can shoehorn it into my code. My design’s gonna be better now, for sure!Mastery: In response to some specific design pain points, the XYZ pattern was a logical next step and was achieved through a simple refactoring.
Design pattern names provide placeholders or complex abstractions and sets of refactorings. Consider the difference between:We have some tight coupling to the database here. We can probably fix it if we apply these refactorings;extract an interface, extract a method, Extract a class,Replace local with parameterORLet’s apply the Repository pattern to fix it.
Used Regularly or Daily by most respondentsFactory (194)Repository (185)Iterator (139)Adapter/Wrapper (122)Observer (113)Command (106)Singleton (105)Strategy (101)Proxy (91)
It’s possible for the new Singleton(); line to be called more than once.
Here are three example registration commands using an IOC container, in this case StructureMap. If you’re not familiar with IOC containers, they’re basically just factories on steroids, which you configure to create instances of types according to certain rules.In the first case, one new instance of the type is created per thread, or per HTTP request. Thus, in an ASP.NET application, a new DbContext will be created with each new web request, but if we used this same code in a non-web context, such as in an integration test, it would create a single instance per thread. In the second case, the Singleton() call will literally configure the lifetime of the instance to be a singleton, with one and only one instance available for the life of this application. In the last, default case, each new request for an instance will get its own, separate instance of the requested type.The benefit of this approach is that it makes it very clear which objects are configured with which lifetimes, and none of the objects themselves are cluttered with these concerns. The resulting code has less repetition, is simpler, and its classes have fewer responsibilities.
Note – this cannot easily be tested without an actual database instance in place.
How Singleton Is Used Call methods on Instance directly Assign variables to Instance Pass as Parameter
Singleton Structure(thread-safe and fast) Source: http://csharpindepth.com/Articles/General/Singleton.aspx
Singleton Consequences The default implementation not thread-safe Avoid in multi-threaded environments Avoid in web server scenarios (e.g. ASP.NET) Singletons introduce tight coupling among collaborating classes Shameless Plug: But why would you Telerik JustMock can be intentionally write code Singletons are notoriously difficult to test usedcan mocktest with you to only and test Commonly regarded as an anti-pattern certainSingletons tools? premium Violate the Single Responsibility Principle Class is responsible for managing its instances as well as whatever it does Using an IOC Container it is straightforward to avoid the coupling and testability issues
Managing Object Lifetime Using an IOC Container
Strategy: Intent Encapsulate a family of related algorithms Let the algorithm vary and evolve independently from the class(es) that use it Allow a class to maintain a single purpose Single Responsibility Principle (SRP) Also enables Open/Closed Principle (OCP) Learn more about SRP and OCP here: http://pluralsight.com/training/Courses/TableOfContents/principles-oo-design
Strategy : Common Usage Dependency Inversion and Dependency Injection Decouple class dependencies and responsibilitiesRefactoring Steps Create interfaces for each responsibility Inject the implementation of the interface via the constructor Move the implementation to a new class that implements the interface
Hidden Dependencies Classes should declare their dependencies via their constructor Avoid hidden dependencies Anything the class needs but which is not passed into constructor Avoid making non-stateless static calls Avoid directly instantiating classes (except those with no dependencies, like strings) Instead, move these calls to an interface, and call a local instance of the interface
“New is Glue” “new” creates tight coupling between classesBe conscious of theconsequences of using“new”If you need loosecoupling, replace“new” with StrategyPatternhttp://flic.kr/p/aN4Zv
Data Access EvolutionNo separation of concerns: Compile Time Runtime Data access logic baked directly into UI ASP.NET Data Source Controls Classic ASP scripts User Interface Data access logic in UI layer via codebehind ASP.NET Page_Load event ASP.NET Button_Click event Database
Data Access : Helper Classes Compile Time Calls to data made through a utility Runtime Example: Data Access Application Block (SqlHelper) User Interface Logic may still live in UI layer Helper Class Or a Business Logic Layer may make calls to a Data Access Layer which might then call the helper Database
What’s Missing? Compile Time Abstraction! Runtime No way to abstract away data access User Interface Tight coupling Leads to Big Ball of Mud Core Infrastructure system IFooRepository SqlFooRepository Solution: Depend on interfaces, not concrete implementations What should we call such Database interfaces? Repositories!
Repository A Data Access Pattern Separates persistence responsibility from business classes Enables Single Responsibility Principle Separation of Concerns Testability Frequently Separate Interfaces for Each Entity in Application E.g. CustomerRepository, OrderRepository, etc. Or using Generics: IRepository<TEntity> May also organize Repositories based on Reads vs. Writes Bounded Contexts
Repository - Example (1) Create/extend an interface to represent the data access you need (2) Copy the implementation from your class into a new class implementing this interface.(3)Inject the interface using theStrategy Pattern. Use the local fieldof this interface type in place ofprevious implementation code.
Where do Repositories Live? Place interfaces in Core Core includes Model classes and most business logic Core has no dependencies (ideally) Place implementation in Infrastructure Infrastructure references Core UI layer references both Core and Infrastructure Responsible for creating object graph, either manually or via an IOC Container
Proxy A class that controls access to another Implemented via subclass or via delegation using a common interface Frequent use cases: Remote Proxy for web services / network calls Lazy loading implementations Security / access control
Adding Caching to a Repository Caching is frequently added to query methods in repositories Caching logic is a separate concern and should live in a separate class from the main data access logic Proxy pattern provides a straightforward means to control access to the “real” data, versus the cache
Command Represent an action as an object Decouple performing the action from the client that is issuing the command Common scenarios: Delayed execution Logging activity Enabling Undo / Revoke Transaction functionality
Factory: Intent Separate object creation from the decision of which object to create Defer creation of objects Only create them if and when needed Add new classes and functionality without breaking client code Only factory needs to know about new types available Store possible objects to create outside of program Configuration Persistent Storage Plug-in assemblies
Practice PDD Pain Driven DevelopmentIf it’s causing pain, fix it.
References Design Patterns, http://amzn.to/95q9ux Design Patterns Explained, http://amzn.to/cr8Vxb Design Patterns in C#, http://amzn.to/bqJgdU Head First Design Patterns, http://amzn.to/aA4RS6Pluralsight Resources N-Tier Application Design in C# http://bit.ly/Msrwig Design Patterns Library http://bit.ly/vyPEgK SOLID Principles of OO Design http://bit.ly/OWF4la My Blog http://ardalis.com
Summary Design Patterns can be used during refactoring or initial design to improve code quality Become comfortable with a number of design patterns, but focus on the most common ones Use design patterns to address pain in your design, such as tight coupling or excessive repetition Design patterns can be combined in powerful ways, such as Strategy-Proxy-Repository