aoancea / dynamic-decorator Goto Github PK
View Code? Open in Web Editor NEWDynamically create different kinds of decorators
License: MIT License
Dynamically create different kinds of decorators
License: MIT License
This decorator is going to support the logging of inputs and outputs of every method from a class, thus, I define the following interface and its implementation:
public interface IFoo
{
string Bar(string text);
}
public class Foo : IFoo
{
public string Bar(string text)
{
return text;
}
}
Given the above interface, I define the following decorator
public class Foo_IO_Decorator : IFoo
{
private readonly IFoo decorated;
public Foo_IO_Decorator(IFoo decorated)
{
this.decorated = decorated;
}
public string Bar(string text)
{
// TODO: provide a mechanics to log the input
string result = decorated.Bar(text);
// TODO: provide a mechanics to log the output
return result;
}
}
Note: For methods which don't accept any parameters or return void, input and respectively output logging will be NOT be performed.
Below I will describe the Ambient Transaction proposal. Example code can be found here.
I would name this Decorator with Ambient Transaction Pattern
Given we have two repositories which are going to be called to insert a record each from a service. This need to run in a transaction because if either of the repository call fails, the operation need to account for neither.
I will outline below the two cases.
Common code:
public interface ISquareRepository
{
void Upsert(Square square);
}
public interface IRectangleRepository
{
void Upsert(Rectangle square);
}
public interface ITransactionService
{
void InsertSquareAndRectangle(Square square, Rectangle rectangle);
}
Unit of Work with Repository Pattern
public class UnitOfWorkTransactionService : ITransactionService
{
private readonly IUnitOfWorkFactory unitOfWorkFactory;
public UnitOfWorkTransactionService(IUnitOfWorkFactory unitOfWorkFactory)
{
this.unitOfWorkFactory = unitOfWorkFactory;
}
public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
{
using(IUnitOfWork unitOfWork = unitOfWorkFactory.Create())
{
unitOfWork.SquareRepository.Upsert(new Square());
unitOfWork.RectangleRepository.Upsert(new Rectangle());
unitOfWork.SaveChanges();
}
}
}
Note: The repositories do not call .SaveChanges() on the DbContext, but it is the duty of the Unit of Work as seen in the example
Ambient Transaction
public class TransactionService : ITransactionService
{
private readonly ISquareRepository squareRepository;
private readonly IRectangleRepository rectangleRepository;
public UnitOfWorkTransactionService(ISquareRepository squareRepository, IRectangleRepository rectangleRepository)
{
this.squareRepository = squareRepository;
this.rectangleRepository = rectangleRepository;
}
public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
{
squareRepository.Upsert(new Square());
rectangleRepository.Upsert(new Rectangle());
}
}
The TransactionService's InsertSquareAndRectangle will be wrapped in an Ambient Transaction as present below(Decorator pattern is applied)
public class AmbientTransactionService : ITransactionService
{
private readonly ITransactionService transactionService;
public UnitOfWorkTransactionService(ITransactionService transactionService)
{
this.transactionService = transactionService;
}
public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted }))
{
transactionService.InsertSquareAndRectangle(square, rectangle);
scope.Complete();
}
}
}
In contrast to Unit of Work with Repository Pattern where the repositories do not call .SaveChanges() on the DbContext, here, each repository is going to save its work. We know that when calling .SaveChanges() on the DbContext a transaction will always be created if there isn't one already present, you can't change that as it's standard EF flow. If there is one already created, it will be enlisted in it.
Hence both repository calls save their work inside a single transaction.
This decorator is going to support the logging of time taken by a method from a class to execute, thus, I define the following interface and its implementation:
public interface IFoo
{
string Bar(string text);
}
public class Foo : IFoo
{
public string Bar(string text)
{
return text;
}
}
Before I can talk about the decorator, a mechanism is needed to provide access to data, and more exactly to the elapsed time. For this I define the following interface:
public interface ILogger
{
void Log(Stopwatch sw);
}
Given the above interfaces, I define the following decorator:
public class Foo_Time_Decorator : IFoo
{
private readonly IFoo decorated;
private readonly ILogger logger;
public Foo_Time_Decorator(IFoo decorated, ILogger logger)
{
this.decorated = decorated;
this.logger = logger;
}
public string Bar(string text)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string result = decorated.Bar(text);
sw.Stop();
logger.Log(sw);
return result;
}
}
public class ConsoleLogger : ILogger
{
public void Log(Stopwatch sw)
{
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
class Program
{
static void(string args)
{
IFoo foo = new Foo();
ILogger logger = new ConsoleLogger();
IFoo fooDecorator = new Foo_Time_Decorator(foo, logger);
fooDecorator.Bar("some text");
}
}
When running a console application
, the ElapsedMilliseconds would be displayed in the console.
Note: The wiring of objects will be done using a DI container.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.