Applied patterns in the project

Preview:

Citation preview

APPLIED PATTERNSThe current project implementation

TOPICS SOLID Repository pattern Unit of Work pattern Decorator pattern

SOLID Single Responsibility Principle

“a class should have only a single responsibility” Open/closed Principle

“software entities … should be open for extension, but closed for modification.”

Liskov substitution principle “objects in a program should be replaceable with

instances of their subtypes without altering the correctness of that program.”

Interface segregation principle ““many client-specific interfaces are better than one

general-purpose interface.” Dependency inversion principle

one should “Depend upon Abstractions. Do not depend upon concretions.”

REPOSITORY PATTERN Abstraction data access

Database Services Files Etc.

Hide implementation details

SEPERATION Repository.Database

Database context Initializers Migrations Scripts

Repository.Entities Entity objects (POCO)

Repository.DataAccess Repository abstraction layer

REPOSITORY INTERFACEpublic interface IRepository<TEntity>

where TEntity : class{

IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,

string includeProperties = "");TEntity GetById(object id);TEntity Insert(TEntity entity);TEntity Delete(object id);TEntity Delete(TEntity entityToDelete);void Update(TEntity entityToUpdate);

}

REPOSITORY IMPLEMENTATIONpublic Repository(DatabaseContext context){

this.context = context;

this.dbSet = context.Set<TEntity>();}

DI REGISTRATIONbuilder.RegisterGeneric(typeof(Repository<>))

.As(typeof(IRepository<>));  

builder.RegisterType<DatabaseContext>()

.AsSelf()

.InstancePerLifetimeScope();  

USAGEprotected StoreNewQueueItem( IRepository<ProcessQueue> processQueueRepository, ...){ this.processQueueRepository = processQueueRepository; ...}

...var insertedItem = processQueueRepository .Insert(queueItem);...

UNIT OF WORK PATTERN “A Unit of Work keeps track of everything

you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.”SOURCE: http://www.martinfowler.com/eaaCatalog/unitOfWork.html

Committing changes Handling of transaction

COMMON REPOSITORY USAGEvar insertedItem = processQueueRepository .Insert(queueItem);processQueueRepository.Save();

OR

public virtual TEntity Insert( TEntity entity){ var insertedItem = dbSet.Add(entity); context.SaveChanges(); return insertedItem;}

UNIT OF WORK + REPOSITORYpublic class MyCommand{

private readonly IUnitOfWorkFactory factory; public MyCommand(IUnitOfWorkFactory factory)

{this.factory = factory;

} public void Execute()

{using (var context = this.factory.CreateNew()){

this.DoSomeNiceThings(context); context.Commit();

}}

}  

SOURCE: http://stackoverflow.com/a/4944201/352640

NOT A GOOD IMPLEMENTATION UoW + Repository, great idea Some of the greater developer minds are

opponents Violates some principles

Opaque dependencies Open/closed principle Single Responsibility Principle Nominal abstraction

BETTER IMPLEMENTATION? List of example implementations:

SOURCE: https://lostechies.com/derekgreer/2015/11/01/survey-of-entity-framework-unit-of-work-patterns/

Unit of Work Decorator Works everywhere Close to point of need More control Setup is hard!

DECORATOR PATTERN “…the decorator pattern … allows behavior

to be added to an individual object … without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.”SOURCE: https://en.wikipedia.org/wiki/Decorator_pattern

Extending functionality Adhering SRP

DECORATOR PATTERN CLASS DIAGRAM Decorator implements same interface

DECORATOR PATTERN EXAMPLE/// <summary>/// The 'Component' abstract class/// </summary>abstract class Component{ public abstract void Operation();} /// <summary>/// The 'Decorator' abstract class/// </summary>abstract class Decorator : Component{ protected Component component; public void SetComponent(Component component) { this.component = component; } public override void Operation() { if (component != null) { component.Operation(); } }}static void Main(){ // Create ConcreteComponent and two Decorators ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); // Link decorators d1.SetComponent(c); d2.SetComponent(d1); d2.Operation();}

/// <summary>/// The 'ConcreteComponent' class/// </summary>class ConcreteComponent : Component{ public override void Operation() { Console.WriteLine("ConcreteComponent.Operation()"); }}/// <summary>/// The 'ConcreteDecoratorA' class/// </summary>class ConcreteDecoratorA : Decorator{ public override void Operation() { base.Operation(); Console.WriteLine("ConcreteDecoratorA.Operation()"); }} /// <summary>/// The 'ConcreteDecoratorB' class/// </summary>class ConcreteDecoratorB : Decorator{ public override void Operation() { base.Operation(); AddedBehavior(); Console.WriteLine("ConcreteDecoratorB.Operation()"); } void AddedBehavior() { }}

PUTTING IT ALL TOGETHER Create handler

Query Command

Repository Repository actions

Create decorator Committing changes

USAGE THE TRANSACTION DECORATORpublic class TransactionRequestHandlerDecorator<...> :  IConvertorCommandHandler<...>{    private readonly IConvertorCommandHandler<...> decorated;    private readonly  MyDatabaseContext context;    public TransactionRequestHandlerDecorator(

IConvertorCommandHandler<...> decorated,MyDatabaseContext context)

    {        this.decorated = decorated;        this.context = context;    }

public void Handle(TCommand command){    Log.Debug("Starting new transaction.");    using (var transaction = context.Database.BeginTransaction())    {        try        {            decorated.Handle(command);            context.SaveChanges();            Log.Debug("Saving changes.");            transaction.Commit();            Log.Debug("Comitting the transaction.");        } ...

DECORATOR REGISTRATIONforeach (var commandHandler in commandHandlers){ builder.RegisterGeneric(commandHandler) .Named("commandHandler", typeof(IConvertorCommandHandler<,,>));}

builder.RegisterGenericDecorator( typeof(TransactionRequestHandlerDecorator<,,>),  typeof(IConvertorCommandHandler<,,>),  fromKey: "commandHandler") 

.Named("decorated",  typeof(IConvertorCommandHandler<,,>));  

QUESTIONS?

Recommended