Here is a very interesting video about Dependency Injection (DIP), Inversion of Control (IoC), Test Driven Development (TDD) and how to write your own simple IoC container. And along the way you'll see some cool R# tricks. This is one of the basis NDA stands on and this is a really clear and easy step through conversation on how to implement DIP, and understand the ideas behind it.
http://codebetter.com/blogs/james.kovacs/archive/2008/10/15/dnrtv-episode-126-roll-your-own-ioc-with-me.aspx
Go Watch it!
Thursday, October 16, 2008
James Kovacs talks about ” Roll-Your-Own IoC” on dnrTV
Monday, September 29, 2008
Is NDA in conflict with YAGNI?
I got a question on my previous post (The No Dependency Architecture (NDA)) if NDA is not in conflict with YAGNI, and when I was writing the response it became more or less an actual post, so there you go :)
Explaining the thought behind the No Dependency Architecture (NDA) in combination with YAGNI in one sentence would be something like this: “You anticipate change at a technical level, not at a functional level”.
I believe that the “You Ain’t Gonna Need It” (YAGNI) principle does not imply that writing software accordingly to the SOLID principles is bad practice. When you are following these principles (and there are others that are good to follow too) then you are writing software that assumes change, right? I believe that YAGNI is more targeted to functional overhead.
I.e. using a IoC container to fulfill the Dependency Inversion Principle (DIP) is not in conflict with YAGNI because that is at a technical level, but when you are writing extra code for no other reason than that you assume the object might be used in a certain other way also, then you are violating the YAGNI principle because then you are creating additional functionality that is not needed.
From Wikipedia ( http://en.wikipedia.org/wiki/You_Ain't_Gonna_Need_It) YAGNI, short for 'You Ain't Gonna Need It', suggests to programmers that they should not add functionality until it is necessary
So I would recommend using the various SOLID principles when writing your software assuming things will change because that is just good practice. Change is a fact, we just don’t know what will change, but by conforming to SOLID we can handle these future changes without too much headache.
As to using an Event Driven Architecture, I am surely not saying each object should only interact using events, that would not make much sense, but most (larger) systems will be build up using multiple sub systems. Having these sub systems communicate via events is a very good way to isolate them from each other. Then it is unknown to each sub system who they are really talking to (i.e. dispatching the events to). In fact it is a 1 to n relationship where the dispatched event might have no, one or many subscribers.
To make the actual handling of subscribing and publishing easier you could use a service bus that deal with that for you. This will also make the system easier adaptable to change. You can also specify that the event can be handled by any instance of the same subscriber enabling load balancing.
“Don’t call us, we call you” ( http://en.wikipedia.org/wiki/Hollywood_Principle); is the basis of an Event Driven Architecture, and this is very true, because no system is waiting on an answer from another system. They fire events and they act on events, it is merely coincidence if these events have anything to do with each other.
So I would also recommend using an Event Driven Architecture (EDA) straight from the beginning, perhaps not using a service bus from the start, but just using EDA will make refactoring to use one at a later stage a lot easier.
Tuesday, August 26, 2008
DDD and BDD with Dan North of Thoughtworks
Yesterday I enjoyed my first NNUG (Norwegian .Net User Group) meeting and it was a great one! Dan North was there to hold a presentation on DDD (Domain Driven Design) and BDD (Behaviour Driven Development). Dan is the inventor of the BDD term so there was _not_ a lot lost in translation :) (disclaimer: if someone else invented the term than it is my mistake in trusting Google) Dan is a very good speaker that puts a great mix of humour and knowledge into his lecture, I would highly recommend people to go and joing his presentations when possible.
After the arranged agenda a subset of the group joined Dan to a pub and went on till twelve. This part may have been even more interesting than the actual presentation ;)
What is Behaviour-Driven Development?
“It’s about focusing on the behaviour of an application from the point of view of its stakeholders”
- Dan North
Monday, April 28, 2008
Composite Pattern
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. Say you have several different types of objects that together form a structure, for example a tree. Take a look at my example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | namespace Composite { public class Branch { private readonly List<object> _Children; public Branch() { _Children = new List<object>(); } public void Add(object item) { _Children.Add(item); } public void Display() { Display(1); } public void Display(int level) { Console.WriteLine(new string('-', level) + " Branch"); level++; foreach (object child in _Children) { Branch branch = child as Branch; if (branch != null) { branch.Display(level); continue; } Leaf leaf = child as Leaf; if (leaf != null) { leaf.Display(level); continue; } Apple apple = child as Apple; if (apple != null) { apple.Display(level); continue; } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace Composite { public class Leaf { public void Display() { Display(1); } public void Display(int level) { Console.WriteLine(new string('-', level) + " Leaf"); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace Composite { public class Apple { public void Display() { Display(1); } public void Display(int level) { Console.WriteLine(new string('-', level) + " Apple"); } } } |
1 2 3 4 5 6 7 8 | namespace Composite { public interface IDisplayItem { void Display(); void Display(int level); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace Composite { public class DisplayItem : IDisplayItem { public virtual void Display() { Display(1); } public virtual void Display(int level) { throw new NotImplementedException(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | namespace Composite { public class Branch : DisplayItem { private readonly List<DisplayItem> _Children; public Branch() { _Children = new List<DisplayItem>(); } public void Add(DisplayItem item) { _Children.Add(item); } public override void Display(int level) { Console.WriteLine(new string('-', level) + " Branch"); level++; foreach (DisplayItem child in _Children) { child.Display(level); } } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Composite { public class Leaf : DisplayItem { public override void Display(int level) { Console.WriteLine(new string('-', level) + " Leaf"); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Composite { public class Apple : DisplayItem { public override void Display(int level) { Console.WriteLine(new string('-', level) + " Apple"); } } } |
http://www.dofactory.com/Patterns/PatternComposite.aspx
http://sourcemaking.com/design_patterns/composite
Thursday, April 24, 2008
Specification Pattern using Spring.Net
After creating my previous post about the Specification Pattern I was thinking that it would be cool if we could use Spring.Net to actually provide the specification. Well after a little looking around I found the solution. I’ll only post the modifications that I made to the code from my last post. Take a look at the example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 | namespace Specification { public class SpecificationFactory { public ISpecification GetSpecification() { using (IApplicationContext ctx = ContextRegistry.GetContext()) { return (ctx.GetObject("Specification") as ISpecification); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | namespace Specification { public class SelectFromList { private readonly List<IUser> _Users; public SelectFromList() { _Users = new List<IUser>(); _Users.Add(new User() { FirstName="Mark", LastName="Nijhof", Age=31 }); _Users.Add(new User() { FirstName = "Mona", LastName = "Nijhof", Age = 30 }); _Users.Add(new User() { FirstName = "Milo", LastName = "Nijhof", Age = 2 }); _Users.Add(new User() { FirstName = "Thalia", LastName = "Nijhof", Age = 1 }); } public List<IUser> GetUsers(ISpecification specification) { List<IUser> result = new List<IUser>(); foreach (IUser user in _Users) { if (specification.IsSatisfiedBy(user)) { result.Add(user); } } return (result); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <configuration> <configSections> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" /> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /> </sectionGroup> </configSections> <spring> <context> <resource uri="config://spring/objects" /> </context> <objects xmlns="http://www.springframework.net"> <object id="Specification" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> <property name="TargetObject" ref="StartWith"/> <property name="TargetMethod" value="And"/> <property name="Arguments" ref="JongerThanWrapper" /> </object> <object id="JongerThanWrapper" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> <property name="TargetObject" ref="JongerThan"/> <property name="TargetMethod" value="Or"/> <property name="Arguments" ref="OlderThan" /> </object> <object name="StartWith" type="Specification.StartWith, Specification" /> <object name="OlderThan" type="Specification.OlderThan, Specification" /> <object name="JongerThan" type="Specification.JongerThan, Specification" /> </objects> </spring> </configuration> |
I hope you found these examples helpful. Also take a look at the following links:
http://www.springframework.net/
http://www.springframework.net/doc-1.1-P2/api/html/Spring.Objects.Factory.Config.MethodInvokingFactoryObject.html
Specification Pattern
The Specification pattern is a very powerful design pattern which can be used to remove a lot of cruft from a class’s interface while decreasing coupling and increasing extensibility. It’s primary use is to select a subset of objects based on some criteria, and to refresh the selection at various times. Take a look at the example below:
1 2 3 4 5 6 7 8 9 | namespace Specification { public interface IUser { string FirstName { get; set; } string LastName { get; set; } int Age { get; set; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | namespace Specification { public class SelectFromList { private readonly List<IUser> _Users; public SelectFromList() { _Users = new List<IUser>(); _Users.Add(new User() { FirstName="Mark", LastName="Nijhof", Age=31 }); _Users.Add(new User() { FirstName = "Mona", LastName = "Nijhof", Age = 30 }); _Users.Add(new User() { FirstName = "Milo", LastName = "Nijhof", Age = 2 }); _Users.Add(new User() { FirstName = "Thalia", LastName = "Nijhof", Age = 1 }); } public List<IUser> GetUsers() { List<IUser> result = new List<IUser>(); foreach (IUser user in _Users) { if (user.FirstName.StartsWith("M") && (user.Age > 10 || user.Age < 2)) { result.Add(user); } } return (result); } } } |
1 2 3 4 5 6 7 8 9 10 11 | namespace Specification { public interface ISpecification { bool IsSatisfiedBy(IUser candidate); ISpecification And(ISpecification other); ISpecification Or(ISpecification other); ISpecification Not(ISpecification other); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | namespace Specification { public class Specification : ISpecification { public virtual bool IsSatisfiedBy(IUser candidate) { throw new NotImplementedException(); } public ISpecification And(ISpecification other) { return new AndSpecification(this, other); } public ISpecification Or(ISpecification other) { return new OrSpecification(this, other); } public ISpecification Not(ISpecification other) { return new NotSpecification(this, other); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace Specification { public class AndSpecification : Specification { private readonly ISpecification _One; private readonly ISpecification _Other; public AndSpecification(ISpecification one, ISpecification other) { _One = one; _Other = other; } public override bool IsSatisfiedBy(IUser candidate) { return _One.IsSatisfiedBy(candidate) && _Other.IsSatisfiedBy(candidate); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace Specification { public class OrSpecification : Specification { private readonly ISpecification _One; private readonly ISpecification _Other; public OrSpecification(ISpecification one, ISpecification other) { _One = one; _Other = other; } public override bool IsSatisfiedBy(IUser candidate) { return _One.IsSatisfiedBy(candidate) || _Other.IsSatisfiedBy(candidate); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace Specification { public class NotSpecification : Specification { private readonly ISpecification _One; private readonly ISpecification _Other; public NotSpecification(ISpecification one, ISpecification other) { _One = one; _Other = other; } public override bool IsSatisfiedBy(IUser candidate) { return _One.IsSatisfiedBy(candidate) && !_Other.IsSatisfiedBy(candidate); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Specification { public class StartWith : Specification { public override bool IsSatisfiedBy(IUser candidate) { return (candidate.FirstName.StartsWith("M")); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Specification { public class OlderThan : Specification { public override bool IsSatisfiedBy(IUser candidate) { return (candidate.Age > 10); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Specification { public class JongerThan : Specification { public override bool IsSatisfiedBy(IUser candidate) { return (candidate.Age < 2); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | namespace Specification { public class SelectFromList { private readonly List<IUser> _Users; public SelectFromList() { _Users = new List<IUser>(); _Users.Add(new User() { FirstName="Mark", LastName="Nijhof", Age=31 }); _Users.Add(new User() { FirstName = "Mona", LastName = "Nijhof", Age = 30 }); _Users.Add(new User() { FirstName = "Milo", LastName = "Nijhof", Age = 2 }); _Users.Add(new User() { FirstName = "Thalia", LastName = "Nijhof", Age = 1 }); } public List<IUser> GetUsers(ISpecification specification) { List<IUser> result = new List<IUser>(); foreach (IUser user in _Users) { if (specification.IsSatisfiedBy(user)) { result.Add(user); } } return (result); } } } |
1 2 3 4 5 | ISpecification startsWith = new StartWith(); ISpecification olderThan = new OlderThan(); ISpecification jongerThan = new JongerThan(); SFL.GetUsers(startsWith.And(olderThan.Or(jongerThan))); |
I hope you found these examples helpful. Also take a look at the following links:
http://www.martinfowler.com/apsupp/spec.pdf
http://www.mattberther.com/2005/03/25/the-specification-pattern-a-primer/
http://en.wikipedia.org/wiki/Specification_pattern
Fluent Interfaces
What is a Fluent Interface, well is basically means that you can execute a method on an object and that that object would return itself to the caller, by doing so the client can chain multiple commands to each other. This will make the code (if implemented correctly) easier to read, please take a look at the example of a Fluent Interface below:
1 2 3 4 5 6 7 8 9 | namespace FluentInterfaces { public interface IOrder { IOrder ShipAddress(IAddress address); IOrder BillAddress(IAddress address); IOrder AddItem(IItem item); } } |
1 2 3 4 5 6 7 8 9 | namespace FluentInterfaces { public interface IAddress { IAddress Street(string street); IAddress PostalCode(string postalCode); IAddress City(string city); } } |
1 2 3 4 5 6 7 8 9 | namespace FluentInterfaces { public interface IItem { IItem ProductID(int id); IItem Price(double price); IItem NubmerOfItems(int count); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | namespace FluentInterfaces { public class Order : IOrder { private IAddress _ShipAddress; private IAddress _BillAddress; private readonly List<IItem> _Items; public Order() { _Items = new List<IItem>(); } public IOrder ShipAddress(IAddress address) { _ShipAddress = address; return (this); } public IOrder BillAddress(IAddress address) { _BillAddress = address; return (this); } public IOrder AddItem(IItem item) { _Items.Add(item); return (this); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace FluentInterfaces { public class Address : IAddress { private string _Street; private string _PostalCode; private string _City; public IAddress Street(string street) { _Street = street; return (this); } public IAddress PostalCode(string postalCode) { _PostalCode = postalCode; return (this); } public IAddress City(string city) { _City = city; return (this); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace FluentInterfaces { public class Item : IItem { private int _Id; private double _Price; private int _Count; public IItem ProductID(int id) { _Id = id; return (this); } public IItem Price(double price) { _Price = price; return (this); } public IItem NubmerOfItems(int count) { _Count = count; return (this); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | namespace FluentInterfaces { class Program { static void Main(string[] args) { IOrder order = new Order() .ShipAddress(new Address() .Street("Burggraaf 12") .PostalCode("7371CW") .City("Loenen")) .BillAddress(new Address() .Street("Burggraaf 12") .PostalCode("7371CW") .City("Loenen")) .AddItem(new Item() .ProductID(1) .Price(15.40) .NubmerOfItems(2)) .AddItem(new Item() .ProductID(132) .Price(101.10) .NubmerOfItems(1)); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace FluentInterfaces { class Program { static void Main(string[] args) { IOrder order = new Order().ShipAddress(new Address().Street("Burggraaf 12").PostalCode("7371CW").City("Loenen")).BillAddress(new Address().Street("Burggraaf 12").PostalCode("7371CW").City("Loenen")).AddItem(new Item().ProductID(1).Price(15.40).NubmerOfItems(2)).AddItem(new Item().ProductID(132).Price(101.10).NubmerOfItems(1)); } } } |
http://martinfowler.com/bliki/FluentInterface.html
http://www.bofh.org.uk/articles/2005/12/21/fluent-interfaces
Wednesday, April 23, 2008
Adapter Pattern
The pattern states: the Adapter pattern adapts one interface for a class into one that a client expects. An adapter allows classes to work together that normally could not because of incompatible interfaces by wrapping its own interface around that of an already existing class. Take a look at the example below:
1 2 3 4 5 6 7 8 9 10 | namespace Adapter { public class Client { public void StartWorkerProcess(IWorker worker) { worker.StartWork(); } } } |
1 2 3 4 5 6 7 | namespace Adapter { public interface IWorker { void StartWork(); } } |
1 2 3 4 5 6 7 8 9 10 | namespace Adapter { public class Worker : IWorker { public void StartWork() { Console.WriteLine("Start working"); } } } |
1 2 3 4 5 6 7 | namespace Adapter { public interface IOtherWorker { void Start(string message); } } |
1 2 3 4 5 6 7 8 9 10 | namespace Adapter { public class OtherWorker : IOtherWorker { public void Start(string message) { Console.WriteLine("Start working on: " + message); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace Adapter { public class OtherWorkerAdapter : IWorker { private readonly IOtherWorker _OtherWorker; public OtherWorkerAdapter() { _OtherWorker = new OtherWorker(); } public void StartWork() { _OtherWorker.Start("Initiated from OtherWorkerAdapter"); } } } |
http://www.dofactory.com/Patterns/PatternAdapter.aspx
Strategy Pattern
The pattern states: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. Look at the below example demonstrating a potential problem:
1 2 3 4 5 6 7 8 9 10 | namespace Strategy { public class Logger { public void Log(string logMessage) { Console.WriteLine(logMessage); } } } |
1 2 3 4 5 6 7 | namespace Strategy { public interface ILogHandler { void Log(string logMessage); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | namespace Strategy { public class Logger { private ILogHandler _LogHandler; public void SetLogHandler(ILogHandler logHandler) { _LogHandler = logHandler; } public void Log(string logMessage) { if (_LogHandler != null) { _LogHandler.Log(logMessage); } } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Strategy { public class ConsoleLogger : ILogHandler { public void Log(string logMessage) { Console.WriteLine(logMessage); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace Strategy { public class FileLogger : ILogHandler { public void Log(string logMessage) { // Log to file functionality } } } |
http://www.dofactory.com/Patterns/PatternStrategy.aspx
http://patnys.com/archive/2008/04/15/strategy-pattern.aspx
Decorator Pattern
The pattern states: Attach additional responsibilities to an object dynamically. The Decorator Pattern is used for adding additional functionality to a particular object as opposed to a class of objects. It is easy to add functionality to an entire class of objects by subclassing an object, but it is impossible to extend a single object this way. With the Decorator Pattern, you can add functionality to a single object and leave others like it unmodified. Below is an example of a drawing program that can draw a square:
1 2 3 4 5 6 7 | namespace Decorator { public interface IShape { void Draw(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace Decorator { public class Square : IShape { private readonly int _Size; public Square(int size) { _Size = size; } public void Draw() { Console.WriteLine("Draw square, size:" + _Size); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace Decorator { public class Decorator : IShape { private readonly IShape _Shape; public Decorator(IShape shape) { _Shape = shape; } public virtual void Draw() { _Shape.Draw(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | namespace Decorator { public class AddFill : Decorator { public AddFill(IShape shape) : base(shape) { } public override void Draw() { base.Draw(); Console.WriteLine("Add fill to IShape object"); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | namespace Decorator { public class AddShadow : Decorator { public AddShadow(IShape shape) : base(shape) { } public override void Draw() { Console.WriteLine("Add shadow to IShape object"); base.Draw(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | namespace Decorator { class Program { static void Main(string[] args) { IShape squareShape = new Square(100); squareShape.Draw(); Console.WriteLine(); IShape addFill = new AddFill(squareShape); addFill.Draw(); Console.WriteLine(); IShape addShadow = new AddShadow(addFill); addShadow.Draw(); Console.ReadKey(); } } } |
1 2 3 4 5 6 7 8 | Draw square, size:100 Draw square, size:100 Add fill to IShape object Add shadow to IShape object Draw square, size:100 Add fill to IShape object |
http://www.dofactory.com/Patterns/PatternDecorator.aspx
http://www.patnys.com/archive/2008/04/21/decorator-pattern.aspx
Monday, April 21, 2008
Law Of Demeter
The principle states: Each unit should only talk to its friends; Don’t talk to strangers. A method of an object should invoke only the methods of the following kinds of objects:
-
1. itself
2. its parameters
3. any objects it creates/instantiates
4. its direct component objects
1 2 3 4 5 6 7 8 9 | namespace LOD { public interface IOrderManager { void AddItemToOrder(IItem item); void RemoveItemFromOrder(IItem item); void ChangeItemName(IItem item, string name); } } |
1 2 3 4 5 6 7 | namespace LOD { public interface IOrder { List<IItem> Items { get; set; } } } |
1 2 3 4 5 6 7 8 | namespace LOD { public interface IItem { int Id { get; set; } string Name { get; set; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace LOD { public class Item : IItem { private int _Id; private string _Name; public int Id { get { return _Id; } set { _Id = value; } } public string Name { get { return _Name; } set { _Name = value; } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | namespace LOD { public class Order : IOrder { private List<IItem> _Items; public List<IItem> Items { get { return _Items; } set { _Items = value; } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | namespace LOD { public class OrderManager : IOrderManager { private readonly IOrder _Order; public OrderManager() { _Order = new Order(); _Order.Items = new List<IItem>(); } public void AddItemToOrder(IItem item) { if (_Order.Items != null) { if ( ! _Order.Items.Contains(item)) { _Order.Items.Add(item); } } } public void RemoveItemFromOrder(IItem item) { if (_Order.Items != null) { if (_Order.Items.Contains(item)) { _Order.Items.Remove(item); } } } public void ChangeItemName(IItem item, string name) { if (_Order.Items != null) { if (_Order.Items.Contains(item)) { _Order.Items[_Order.Items.IndexOf(item)].Name = name; } } } } } |
1 2 3 4 5 6 7 8 9 | namespace LOD { public interface IOrder { void AddItem(IItem item); void RemoveItem(IItem item); void ChangeItemName(IItem item, string name); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | namespace LOD { public class Order : IOrder { private List<IItem> _Items; public Order() { _Items = new List<IItem>(); } public void AddItem(IItem item) { if (_Items != null) { if (!_Items.Contains(item)) { _Items.Add(item); } } } public void RemoveItem(IItem item) { if (_Items != null) { if (_Items.Contains(item)) { _Items.Remove(item); } } } public void ChangeItemName(IItem item, string name) { if (_Items != null) { if (_Items.Contains(item)) { _Items[_Items.IndexOf(item)].Name = name; } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace LOD { public class OrderManager : IOrderManager { private readonly IOrder _Order; public OrderManager() { _Order = new Order(); } public void AddItemToOrder(IItem item) { _Order.AddItem(item); } public void RemoveItemFromOrder(IItem item) { _Order.RemoveItem(item); } public void ChangeItemName(IItem item, string name) { _Order.ChangeItemName(item, name); } } } |
I hope you found these examples helpful. Also take a look at the following link:
http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf
Dependency Inversion Principle using Spring.Net
This post will continue from my previous post about how to implement the Dependency Inversion Principle. Below you will see an example that is in the same state as where my previous post ended, only I created a different context to make its usefulness more clear.
1 2 3 4 5 6 7 8 9 10 | namespace SpringDIP { public interface IDatabaseOperations { void Update(string[] parameters); void Delete(int id); string[] Select(int id); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | namespace SpringDIP { public class MsSqlDatabaseProvider : IDatabaseOperations { public void Update(string[] parameters) { // Do a Microsoft SQL Server 2008 specific update } public void Delete(int id) { // Do a Microsoft SQL Server 2008 specific delete } public string[] Select(int id) { // Do a Microsoft SQL Server 2008 specific select return (new string[] { "1", "Microsoft" }); } } } |
1 2 3 4 5 6 7 8 9 10 | namespace SpringDIP { public class DatabaseProviderFactory { public IDatabaseOperations GetDatabaseProvider() { return (new MsSqlDatabaseProvider()); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using Spring.Context; using Spring.Context.Support; namespace SpringDIP { public class DatabaseProviderFactory { public IDatabaseOperations GetDatabaseProvider() { using (IApplicationContext ctx = ContextRegistry.GetContext()) { return(ctx.GetObject("DatabaseProvider") as IDatabaseOperations); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <configuration> <configSections> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" /> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /> </sectionGroup> </configSections> <spring> <context> <resource uri="config://spring/objects" /> </context> <objects xmlns="http://www.springframework.net"> <object name="DatabaseProvider" type="SpringDIP.MsSqlDatabaseProvider, SpringDIP" /> </objects> </spring> </configuration> |
I hope you found these examples helpful. Also take a look at the following links:
http://springframework.net/
http://www.developer.com/net/csharp/article.php/10918_3722931_1
