370 likes | 620 Views
Design Patterns in Practice. By Doug, Jeremy, & Mike. What is a design pattern?. A design pattern is a reusable solution to a common problem in software design. A design pattern is not code. A design pattern can vary in scope from very simplistic to an entire system.
E N D
Design Patterns in Practice By Doug, Jeremy, & Mike
What is a design pattern? • A design pattern is a reusable solution to a common problem in software design. • A design pattern is not code. • A design pattern can vary in scope from very simplistic to an entire system.
The different kinds of patterns • Creational • Patterns that focus on object creation. • Structural • Patterns that focus on the relationships between entities. • Behavioral • Patterns that focus on the communication patterns between objects. • Concurrency • Patterns that deal with multi-threaded programming techniques.
What are the benefits? • Can significantly speed up the development process. • Wide adoption of common patterns result in code that is easier to understand and maintain over time. • Proper usage of design patterns will result in a better overall design.
What are the drawbacks? • Can introduce more levels of indirection. • Improper usage will negate the benefits. • Adding complex design patterns to simple problems can result in over engineering.
The Interface • What is it? • An interface contains only the signatures of methods, properties, events or indexers. • It is a contract between you and the rest of the world. • Why should you use it? • It insulates the rest of the world from the underlying implementation. • When should you use it? • Whenever you are needing to isolate yourself.
The Interface vs. Abstract Classes • The problem setup: • A group of physicians want to have a document management system to keep track of their publications.
1 week later… • Can we have third party authored documents about us in our system?
After 2 months of sheer bliss… • Can we have procedure and diagnosis information on the documents that are related to procedures they have performed?
Our code is starting to cave… • There are dozens of places in our code that have logic similar to the following: publicvoidProcessDocument(Document doc) { if (doc isAuthoredDocument) { // Do author specific stuff... } if (doc isMedicalDocument) { // Do medical stuff... } if (doc is PhysicianDocument) { // Do physician stuff... } } This is dangerous!
1 day later… • Can we have patient related documents for the procedures we have done or have found on-line? ?
What we could have done… if (doc isIMedicalDocument) { // Do medical stuff... } if (doc isIPhysicianDocument) { // Do physician stuff... }
The Singleton • The singleton pattern is used to restrict the number of instances of a class to one. • How is this useful? • Why is this controversial?
The Singleton - Implementation • Singleton C# code publicsealedclassSingleton { privatestaticreadonlySingletonm_instance = newSingleton(); ///<summary> /// Explicit static constructor to tell C# compiler /// not to mark this type as beforefieldinit ///</summary> static Singleton() { } ///<summary> /// Private constructor to enforce singleton pattern. ///</summary> private Singleton() { } ///<summary> /// Static property to return the singleton instance. ///</summary> publicstaticSingleton Instance { get { returnm_instance; } } }
The Factory • The factory pattern is a creational pattern that uses a singleton object to provide implementations of a requested interface to a caller. • What are some common uses for a factory? • Logging • Configuration • Data access • Testing • What does the factory help with? • Returning Interface implementations • Simplifies complex object creation • Caching
The Factory in Data Access // Retrieve our DAO from the factory. IPersonDAOdao = DAOFactory.GetInstance.GetDAO<IPersonDAO>(); // Invoke the appropriate retrieval method. • IPersonperson =dao.GetPerson(modelId);
Other Factory Uses Create fake implementations instead of waiting Test really hard scenarios
The Delegate • The delegate pattern is a technique where an object expresses certain behavior, but in reality delegates the responsibility for implementing/executing that behavior to an associated object. • What does the delegate help with? • Separation of concerns • Reuse of common logic • What are some common uses for a delegate? • Data access • Business layer delegates • Asynchronous programming
The Delegate Inside the DAO publicIPersonGetPerson(GuidmodelId) { // Construct our delegate that can fill out our request // and empty out the response from the data source. • GetPersonDataDelegatedel = newGetPersonDataDelegate(modelId); // Obtain a reference to the call point by passing the delegate IDataCall<IPerson> call = DataCallFactory.Instance.GetDataCall(del); // Execute the call and return the result. returncall.Execute(); }
A Common Problem • How should I instrument my code? • The real problems are… • What should I capture? • Where should I store the captured data? • Who should I notify when things go bad? • What does bad mean? • How do I change the system behavior to optimize the system resources that are available to me? • How do I keep my code clean???
A Common Solution publicvoid Execute() { DateTimestartedOn = DateTime.UtcNow; Loggerlogger = newLogger(); try { logger.Write(string.Format( "Starting GetPerson([{0}]) at {1}", m_modelId, DateTime.UtcNow)); // Execute call logger.Write(string.Format( "Finished GetPerson([{0}]) at {1} and it worked!", m_modelId, DateTime.UtcNow)); } catch (Exception e) { logger.Write(string.Format("GetPerson([{0}]) failed {1}.", m_modelId, e)); throw; } finally { DateTimeendedOn = DateTime.UtcNow; TimingSystem.GetInstance().LogExecutionTime("GetPerson", endedOn.Subtract(startedOn)); } } What if my logger doesn’t support my needs right now? What if this was slow? Should we let someone know about this? Who was the user?
A Better Solution - The Interceptor • First, design the core system without any instrumentation. • Next, identify the key points in the call stack; these are the interception points. • Finally, identify important information to communicate at the interception points.
Interceptor Implementations • More can be added dynamically at run time.
Using Our Interceptor • Much cleaner and more extensible publicvoid Execute() { IContextctx = Dispatcher.GetInstance().CreateContext(m_modelId); try { Dispatcher.Started(ctx); // Execute call Dispatcher.Ended(ctx); } catch (Exception e) { Dispatcher.Errored(ctx, e); throw; } }
Service Oriented Architecture • What is it?
SOA - Simplified • A simplistic view of one service What is a model? Why do you have all of these layers?
Proper Coupling • Loose coupling is one of the tenants; however, appropriate sacrifices can be made to achieve performance goals. Is this allowed?
Bad SOA! • You must adhere to the design pattern or your implementation will collapse under its own weight.
Database Loose Coupling • Some data integrity checks must be moved to higher levels in the architecture. What if an account is removed?
Loose Coupling Wrap-up • True loose coupling is not easy. • An event model must be part of your solution to achieve truly isolated services. • Performance and extensibility are often at odds with each other. • These design patterns are really powerful!
Future Topics • Unit Testing • SOA Deep Dive • Pub / Sub • Business Intelligence / Analytics • Free Text Search