Nu we de Data Layer af hebben, kunnen we ons richten op de laag erboven: de Business Layer. We hebben al een gedeelte van de Business Layer geïmplementeerd, namelijk de BusinessObjects.

Naast de BusinessObjects bevat de Business Layer ook nog een soort façade. Deze façade wordt geïmplementeerd in OrderSystem.BusinessLayer.

In ons geval hebben we 1 façade object die verantwoordelijk is voor alle bewerkingen die op een Order worden uitgevoerd (waaronder ook acties op de OrderDetail). Waar we ook nog rekening mee gaan houden is dat op het moment dat je een lijst met orders ophaalt, je nog niet alle OrderDetails hoeft op te halen. Dat zal bij een kleine lijst niet zo’n probleem zijn, maar als de lijst groter wordt kan het behoorlijk schelen in de hoeveelheid data die je wel op niet ophaalt. Ook scheelt het weer DataAccess. Dit gebeuren wordt ook wel Lazy Loading genoemd. Om dit te realiseren gaan we een soort Proxy object maken voor de OrderDetailLijst. Allereerst hebben we een abstracte class ProxyList nodig. Hierin wordt de interface bepaald en ook al generieke onderdelen geïmplementeerd.

Eerst moeten we nog een tweetal references toevoegen aan OrderSystem.BusinessLayer, namelijk: OrderSystem.DataLayer en OrderSystem.BusinessLayer.BusinessObjects en OrderSystem.Framework.Transactions.
Maak in de OrderSystem.BusinessLayer.BusinessObjects een nieuwe class met de naam ProxyList. De class ziet er als volgt uit:

using System;
using System.Collections.Generic;
using System.Text;
namespace OrderSystem.BusinessLayer.BusinessObjects
{
///
/// ProxyList represents a generic list that is loaded from the database.
/// It implements a pattern called lazy loading (also called just-in-time loading).
/// Lazy loading is a way to control how and when a list is loaded with the goal
/// to load it only when it''s absolutely necessary. This way the class prevent the
/// application from executing unneccessary database hits. It''s a way to better
/// manage limited resources.
///
/// ProxyList is used in the Customer business object to hold a reference to the list of Orders.
/// See ProxyForOrderDetails in the Facade layer.
///
/// ProxyList is also used in the Order business objec to hold a reference to the list of Order Details.
/// See ProxyForOrders in the Facade layer.
///
/// GoF Design Patterns: Proxy.
/// Enterprise Design Patterns: Lazyload.
///
///
/// This class is a Proxy because it ''stands in'' for a limited resource.
/// This class is a Lazy-loader because it does not load when constructed.
///
/// Generic type stored in the list.
public abstract class ProxyList : IList
{
private object _parent;
private IList _list;
private bool _isLoaded = false;
///
/// Default constructor for ProxyList abstract class.
///
public ProxyList()
{
}
///
/// Overloaded constructor for ProxyList abstract class.
///
///
Parent (or owner) of the ProxyList.
public ProxyList(object parent)
{
this.Parent = parent;
}
///
/// Overloaded constructor for ProxyList abstract class.
///
///
Parent (or owner) of the ProxyList.
///
List being proxied.
public ProxyList(object parent, IList list)
{
this.Parent = parent;
this.List = list;
}
///
/// Loads the specific list. To be implemented in derived class.
///
///
protected abstract int LoadList();
///
/// Lazy-loads the list. First checks if the list is already loaded.
///
private void LazyLoad()
{
if (!_isLoaded)
LoadList();
}
///
/// Gets or sets the types list or types being proxied.
///
public IList List
{
get { return _list; }
set
{
_list = value;
_isLoaded = true;
}
}
///
/// Gets or sets the parent class (i.e. the owner) or the ProxyList.
///
public object Parent
{
get { return _parent; }
set { _parent = value; }
}
///
/// Determines the index of a specific item in the list.
///
///
/// Before the operation starts it checks whether list is already loaded.
/// If not, it first lazy-loads the list.
///
///
Item for which index is requested.
/// Index of the item in the list.
public int IndexOf(T item)
{
LazyLoad();
return _list.IndexOf(item);
}
///
/// Inserts an item at the given index in the list.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Index at which item is inserted.
///
Item being inserted.
public void Insert(int index, T item)
{
LazyLoad();
_list.Insert(index, item);
}
///
/// Removes the list item at the specified index.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Index position.
public void RemoveAt(int index)
{
LazyLoad();
_list.RemoveAt(index);
}
///
/// Indexer into list. Get or set item at given index.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Index at which item is located.
/// Type at index location.
public T this[int index]
{
get
{
LazyLoad();
return _list[index];
}
set
{
LazyLoad();
_list[index] = value;
}
}
#region ICollection Members
///
/// Adds an item to the list.
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
///
Item to be added
public void Add(T item)
{
LazyLoad();
_list.Add(item);
}
///
/// Removes all items from the list.
///
public void Clear()
{
if (_isLoaded)
_list.Clear();
}
///
/// Determines whether the list contains a specific item.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Item being looked for.
/// Value indicating whether item is present in list.
public bool Contains(T item)
{
LazyLoad();
return _list.Contains(item);
}
///
/// Copies the element of list into an array starting at a given index.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Generic array being copied into.
///
Start index from which to copy.
public void CopyTo(T[] array, int arrayIndex)
{
LazyLoad();
_list.CopyTo(array, arrayIndex);
}
///
/// Gets the number of elements in the list.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
public int Count
{
get
{
LazyLoad();
return _list.Count;
}
}
///
/// Gets the value indicating whether the list is read-only.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
public bool IsReadOnly
{
get
{
LazyLoad();
return _list.IsReadOnly;
}
}
///
/// Removes the first occurrence of a specific item in the list.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
///
Item being searched for.
/// Value indicating whether item was removed.
public bool Remove(T item)
{
LazyLoad();
return _list.Remove(item);
}
#endregion
#region IEnumerable Members
///
/// Returns a generic enumerator that iterates over the list.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
/// Requested generic enumerator.
public IEnumerator GetEnumerator()
{
LazyLoad();
return _list.GetEnumerator();
}
#endregion
#region IEnumerable Members
///
/// Returns an enumerator that iterates over the list.
///
///
/// Before the operation starts it checks whether list is loaded.
/// If not, it first lazy-loads it.
///
/// Requested enumerator.
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
LazyLoad();
return _list.GetEnumerator();
}
#endregion
}
}

Maak een nieuwe folder aan in OrderSystem.BusinessLayer. Noem deze folder ProxyObjects.
In deze folder wordt een class ProxyForOrderDetails aangemaakt. De code er in is:

using System;
using System.Collections.Generic;
using System.Text;
using OrderSystem.BusinessLayer.BusinessObjects;
using OrderSystem.DataLayer;
namespace OrderSystem.BusinessLayer.ProxyObjects
{
public class ProxyForOrderDetails : ProxyList
{
private IOrderDao orderDao = DataAccess.OrderDao;
private Order _order;
///
/// Constructor for ProxyForOrderDetails.
///
///
Order.
public ProxyForOrderDetails(Order order)
{
_order = order;
}
///
/// Loads the order details associated with an order.
///
/// Number of items loaded.
protected override int LoadList()
{
base.List = (IList<img src="http://blogs.4dotnet.nl/smilies/icon_arrow.gif" alt=">)" />orderDao.GetOrderDetails(_order);
return Count;
}
}
}

Zo, de lazy loading is nu af. We kunnen nu de Façade maken voor Order. Maak in OrderSystem.BusinessLayer een nieuwe class aan die OrderFacade heet. De code is:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using OrderSystem.DataLayer;
using OrderSystem.BusinessLayer.BusinessObjects;
using OrderSystem.BusinessLayer.ProxyObjects;
using OrderSystem.Framework.Transactions;
namespace OrderSystem.BusinessLayer
{
///
/// Facade (also called Service Layer) that controls all access to Order,
/// Order, and Order Details related activities.
///
/// Gof Design Patterns: Facade, Decorator, Proxy
/// Enterprise Design Patterns: Remote Facade, LazyLoad, Service Layer, Transaction Script.
///
///
/// This Facade is not secure. In most applications each method in the
/// Facade should check for access security. This can be accomplished
/// either programmatically or declaratively (using Attributes). In addition,
/// validation of arguments should also be added in each procedure.
///
/// The DataObject and DataObjectMethod Attributes in this class tell the
/// Visual Studio 2005 Wizards which classes and methods are
/// appropriate for building the ObjectDataSource Web controls.
///
/// The Proxy Pattern is used in accessing Orders and Order Details.
///
/// The Decorator Pattern is used in bracketing database transactions with
/// a decorated Transaction scope class.
///
/// The Remote Facade Design Pattern provides a course-grained facade on a
/// fine-grained objects. Indeed the methods are course-grained as they
/// deal with complete entities and/or entity lists rather than their individual
/// attributes.
///
/// The Service Layer Design Pattern is the same as the Facade Design Pattern
/// except that Service Layer is more specific to Enterprise Business Applications
/// in that the layer sits on top of the Domain Model (which is the case here).
///
/// The Transaction Script Design Pattern organizes business logic by procedures
/// where each procedure handles a single request from the presentation. This is
/// exactly how the Facade API has been modeled. They entirely handle individual
/// requests (either from Web Application or Web Service).
///
[DataObject(true)]
public class OrderFacade
{
private IOrderDao orderDao = DataAccess.OrderDao;
[DataObjectMethod(DataObjectMethodType.Select)]
public IList GetOrders()
{
// TODO: add access security here..
IList orders = orderDao.GetOrders();
foreach (Order order in orders)
{
order.OrderDetails = new ProxyForOrderDetails(order);
}
return orders;
}
[DataObjectMethod(DataObjectMethodType.Select)]
public Order GetOrder(int orderID)
{
// TODO: add access security here..
// TODO: add argument validation here..
// Retrieve Order
Order order = orderDao.GetOrder(orderID);
// Assign a Proxy for OrderDetails. Only when OrderDetails are absolutely
// needed will they be retrieved from the database.
order.OrderDetails = new ProxyForOrderDetails(order);
return order;
}
[DataObjectMethod(DataObjectMethodType.Insert)]
public void VoegOrderToe(Order order)
{
// TODO: add security here..
// TODO: add argument validation here..
// Run within the context of a database transaction.
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.VoegOrderToe(order);
transaction.Complete();
}
}
[DataObjectMethod(DataObjectMethodType.Update)]
public void WijzigOrder(Order order)
{
// TODO: add security here..
// TODO: add argument validation here..
// Run within the context of a database transaction
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.WijzigOrder(order);
transaction.Complete();
}
}
[DataObjectMethod(DataObjectMethodType.Delete)]
public void VerwijderOrder(Order order)
{
// TODO: add access security here..
// TODO: add argument validation here..
// Run within the context of a database transaction
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.VerwijderOrder(order);
transaction.Complete();
}
}
[DataObjectMethod(DataObjectMethodType.Update)]
public void BestelOrder(Order order)
{
// TODO: add security here..
// TODO: add argument validation here..
// Run within the context of a database transaction
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.BestelOrder(order);
transaction.Complete();
}
}
[DataObjectMethod(DataObjectMethodType.Update)]
public void MeldOrderBinnen(Order order)
{
// TODO: add security here..
// TODO: add argument validation here..
// Run within the context of a database transaction
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.MeldOrderBinnen(order);
transaction.Complete();
}
}
[DataObjectMethod(DataObjectMethodType.Update)]
public void LeverOrderUit(Order order)
{
// TODO: add security here..
// TODO: add argument validation here..
// Run within the context of a database transaction
// The Decorator Design Pattern.
using (TransactionDecorator transaction = new TransactionDecorator())
{
orderDao.LeverOrderUit(order);
transaction.Complete();
}
}
}
}

Zo, nu hebben we de Business Layer af. De volgende keer gaan we verder met de User Interface, of ook wel de Presentation Layer genoemd.

Stem of voeg toe aanUitleg over het gebruik van deze icons :Voeg dit artikel toe aan Del.icio.us Voeg toe aan je Google bladwijzers Plaats dit bericht op Twitter Geef dit als tip aan je Hyves-vrienden Voeg toe aan je Facebook-profiel Deel met je LinkedIn-contacten Abonneer je op de RSS-feed van deze site Verstuur deze pagina per e-mail via Feedburner Print deze pagina of genereer een PDF-bestand