NothinButDotNetStore, part 2

by andrei 7. July 2008 22:16

This is the second post related to Jean-Paul S. Boodhoo's training application, NothinButDotNetStore.

Tasks:

There is an interesting concept here, the concept of tasks. The ApplicationStartup task is responsible for correctly runninng the application, while the other tasks are similar to Service or Business Logic classes: they implement the business of the application, and create the bridge between the UI and the Model. The Business Logic tasks would probably be extracted into their own project in a bigger application.

For situations when data is retrieved from the database but it has to be reorganised for presentation in the UI, DTOs (Data Transfer Objects) are used. The cool thing here is the implementation of the mappers: they receive information from the model and transform it into information for the UI:

public interface IMapper<Input, Output>
   
{
        Output MapFrom
(Input input);
   
}

public interface IProductDisplayItemDTOMapper : IMapper<IProduct, ProductDisplayItemDTO>
   
{
    }

public class ProductDisplayItemDTOMapper : IProductDisplayItemDTOMapper
    {
       
public ProductDisplayItemDTO MapFrom(IProduct input)
       
{
           
return new ProductDisplayItemDTO(input.Name, input.Description, input.Price, input.Id);
       
}
    }

Web:

There are many discussions in the .Net community about which presentation pattern to use. In this application you will find a front controller implementation.

 

Conclusion:

If you want to improve your OOP skills or you enterprise application design skills, this code is the place to start. Just to review, here are a few things which can be learned from it:

  • how to implement a data access pattern
  • how to write a business domain
  • how to use the visitor pattern
  • how to use DTOs
  • how to implement a DI pattern
  • how to implement a presentation pattern (in this case, front controller)
  • unit testing, BDD, TDD

But there's much more. Here are a few links to get you even more interested:

 

 

Enjoy programming!

 

NothinButDotNetStore, part 1

by andrei 6. July 2008 22:11


I will talk about some of the things I learned from Jean-Paul S. Boodhoo's training application, NothinButDotNetStore.

One thing to notice is that he did not use any framework for the common patterns that are ussualy found in enterprise applications, instead he implemented simple but efficient solutions for each of them. Most of the communication is done through interfaces, which is a great object oriented programming lesson.

This post will cover only a small percent of what this code has to offer, so I suggest you get the source using a SVN client and take your time to review in detail.

DataAccess: He did an implementation of a data access pattern (subdirectories Core and Mapping).

Domain:

Great examples of the visitor pattern:

public interface IValueReturningVisitor<ValueToReturn, T> : IVisitor<T>
     
{
      ValueToReturn GetResult
();
     
}

public class AllItemsInCartVisitor : IValueReturningVisitor<IEnumerable<ICartItem>, ICartItem>
     
{
     
private IRichList<ICartItem> aggregated;
     
public AllItemsInCartVisitor()
     
{
      aggregated
= new RichList<ICartItem>();
     
}
     
public IEnumerable<ICartItem> GetResult()
     
{
     
return aggregated;
     
}
     
public void Visit(ICartItem item)
     
{
      aggregated.Add
(item);
     
}
      }

private IRichList<ICartItem> items;
     
public IEnumerable<ICartItem> AllItems()
     
{
     
return items.GetResultOfVisitingAllItemsWith(new AllItemsInCartVisitor());
     
}

Instead of returning a null when a CartItem is not found, a NonExistantCartItem object is returned (which also implements ICartItem):

private ICartItem found;
     
...
     
return found ?? NonExistantCartItem.Instance;

Infrastructure:

You can find a simple and elegant implementation of a dependency injection mechanism.

Also, check out these cool extensions for IEnumerable which go hand in hand with the visitor classes:

public static class EnumerableExtensionGateway
      {
     
public static void VisitAllItemsUsing<T>(this IEnumerable<T> items,IVisitor<T> visitor)
     
{
     
new EnumerableActions<T>(items).VisitAllItemsUsing(visitor);
     
}
     
public static Result GetResultOfVisitingAllItemsWith<T,Result>(this IEnumerable<T> items,IValueReturningVisitor<Result,T> visitor)
     
{
     
return new EnumerableActions<T>(items).GetResultOfVisitingAllItemsWith(visitor);
     
}
     
public static IEnumerable<T> AllSatisfying<T>(this IEnumerable<T> items,ISpecification<T> specification)
     
{
     
return new EnumerableActions<T>(items).AllMatching(specification);
     
}
     
public static IEnumerable<Output> MapAllUsing<T,Output>(this IEnumerable<T> itemsToMap,IMapper<T,Output> mapper)
     
{
     
return new EnumerableActions<T>(itemsToMap).MapAllUsing(mapper);
     
}
      }

public interface IEnumerableActions<T>
     
{
     
void VisitAllItemsUsing(IVisitor<T> visitor);
     
Result GetResultOfVisitingAllItemsWith<Result>(IValueReturningVisitor<Result, T> visitor);
     
IEnumerable<T> AllMatching(ISpecification<T> specification);
     
IEnumerable<Output> MapAllUsing<Output>(IMapper<T, Output> mapper);
     
}

public class EnumerableActions<T> : IEnumerableActions<T>
     
{
     
private IEnumerable<T> itemsToActOn;
     
public EnumerableActions(IEnumerable<T> itemsToActOn)
     
{
     
this.itemsToActOn = itemsToActOn;
     
}
     
public void VisitAllItemsUsing(IVisitor<T> visitor)
     
{
     
foreach (T t in itemsToActOn)
     
{
      visitor.Visit
(t);
     
}
      }
     
public Result GetResultOfVisitingAllItemsWith<Result>(IValueReturningVisitor<Result,T> visitor)
     
{
      VisitAllItemsUsing
(visitor);
     
return visitor.GetResult();
     
}
     
public IEnumerable<T> AllMatching(ISpecification<T> specification)
     
{
     
foreach (T t in itemsToActOn)
     
{
     
if (specification.IsSatisfiedBy(t)) yield return t;
     
}
      }
     
public IEnumerable<Output> MapAllUsing<Output>(IMapper<T,Output> mapper)
     
{
     
foreach (T t in itemsToActOn)
     
{
      yield
return mapper.MapFrom(t);
     
}
      }
      }

And add the RichList, which is integrated nicely with the rest of the patterns:

public class RichList<T> : List<T>, IRichList<T>
   
{
       
public RichList(IEnumerable<T> collection) : base(collection)
       
{
        }

       
public RichList(int capacity) : base(capacity)
       
{
        }

       
public RichList()
       
{
        }

       
public IEnumerable<Output> MapAllUsing<Output>(IMapper<T, Output> mapper)
       
{
           
return ConvertAll<Output>(mapper.MapFrom);
       
}

       
public new IRichList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
       
{
           
return new RichList<TOutput>(base.ConvertAll(converter));
       
}

       
public new IRichList<T> FindAll(Predicate<T> match)
       
{
           
return new RichList<T>(base.FindAll(match));
       
}

       
public new IRichList<T> GetRange(int index, int count)
       
{
           
return new RichList<T>(base.GetRange(index, count));
       
}

       
public void VisitAllItemWith(IVisitor<T> visitor)
       
{
           
this.foreach(visitor.Visit);
       
}

       
public Result GetResultOfVisitingAllItemsWith<Result>(IValueReturningVisitor<Result, T> visitor)
       
{
            VisitAllItemWith
(visitor);
           
return visitor.GetResult();
       
}
    }

 

 

Enjoy programming!

 

Powered by BlogEngine.NET 1.4.5.0