vineri, 29 ianuarie 2010

Abstract Factory Pattern


Abstract Factory Pattern


Abstract Factory Pattern

About


  • An abstract factory provides an interface for creating families of related objects without specifying their concrete classes.
  • Could be seen as a hierarchy that support multiple environment and produce different suites of products
  • It avoids duplicating the decision making everywhere an instance is created.
  • It is useful for generating different layouts and multiple-look-and-feel user interfaces.



Concrete sample of use for Abstract Factory









































AbstractFactory

ContinentFactory

HandBags Factory

Device

ViewFactory

ConcreteFactories

EuropeFactory, AfricaFactory

GenuineBag Factory, FakeBag Factory

Cassete Device, CD Device, DVD Device

RealTimeViewFactory, ReplayViewFactory

IProduct

Herbivore, Carnivore

HandBagOne, HandBabTwo

Audio Quality, Video Quality

Grid View, Chart View, CSV only View

Product

Deer, Beer, Zebra, Lion

BagTypeOneGenuine, BagTypeTwoGenuine,









BagTypeOneFake, BagTypeTwofake


Cassette Audio Quality, CD Audio Quality, DVD Audio Quality, Cassette Video Quality, CD Video Quality, DVD Video Quality

RealTime Grid View, RealTime Chart View,RealTime CSV only View, ReplayView Grid View,ReplayView Chart View, ReplayView CSV only View

Client

Discovery Animal

Customer

Customer

Application




Sample



Consider an application that has to present some data to a user. The source of data could be a device that gives data in realtime mode or a data store. These data could be presented even in a Chart view or in a Grid view or written to a CSV file.

This is the class diagram








using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Statistics
{
/// <summary>
/// Factory of a family of views that has the same type of provider
/// </summary>
/// <typeparam name="T"></typeparam>
interface IViewFactory<T> where T : IProvider
{
IChartView GetChartView(string i_name, eChartType i_chartType, T i_provider);
IGridView GetGridView(string i_name, T i_provider);
ICSVTextView GetCSVTextView(string i_name, char i_delimiter, T i_provider);
}

/// <summary>
/// Provides value for stats from a specific data source
/// </summary>
public interface IProvider
{
T GetStatValue<T>(int i_index, string i_statName);
}

/// <summary>
/// Common interface for all views
/// </summary>
public interface IView
{
String Name { get; }
void RegisterStats(IEnumerable<String> _statNames);
void DeregisterStats();
void OpenView();
void CloseView();
IList<String> Stats { get; }
IProvider ViewProvider { get; set; }
}

/// <summary>
/// Interface for Chart views
/// </summary>
public interface IChartView : IView
{
eChartType ChartType { get; set; }
}

/// <summary>
/// Interface for Grid views
/// </summary>
public interface IGridView : IView
{
}

/// <summary>
/// Interface for CSV Text view
/// </summary>
public interface ICSVTextView : IView
{
char Delimiter { get; }
}

public enum eChartType
{
kLine,
kBar,
kPie
}

/// <summary>
/// Base implementation common to all providers
/// </summary>
public class BaseProvider : IProvider
{
public virtual T GetStatValue<T>(int i_index, string i_statName)
{
if (typeof(T) == typeof(int))
{
return (T)(object)i_index;
}
if (typeof(T) == typeof(string))
{
return (T)(object)string.Format("{0} at position {1}.", i_statName, i_index);
}
return default(T);
}
}

public abstract class BaseView : IView
{
protected String _name;
protected List<String> _stats;
protected IProvider _provider;
public BaseView(string i_name, IProvider i_provider)
{
_name = i_name;
_provider = i_provider;
Console.WriteLine(GetType() + " view created!");
}

public String Name
{
get { return _name; }
}

public IProvider ViewProvider
{
get { return _provider; }
set { _provider = value; }
}

public virtual void RegisterStats(IEnumerable<String> _statNames) { _stats = new List<String>(_statNames); }
public virtual void DeregisterStats() { if (_stats != null) _stats.Clear(); }
public virtual void OpenView()
{
StringBuilder _sb = new StringBuilder();
_sb.AppendLine("Statistics in view: " + _name);
foreach (string _stat in _stats)
{
_sb.AppendLine("\t" + _stat);
}
Console.WriteLine(_sb.ToString());
}

public abstract void CloseView();

public IList<string> Stats
{
get { return _stats; }
}
}

public class RealTimeProvider : BaseProvider
{
public override T GetStatValue<T>(int i_index, string i_statName)
{
Console.WriteLine(string.Format("GetRealTimeStat {1} at index {0}.", i_statName, i_index));
return base.GetStatValue<T>(i_index, i_statName);
}
}

class DataStoreProvider : BaseProvider
{
public override T GetStatValue<T>(int i_index, string i_statName)
{
Console.WriteLine(string.Format("Get Stat {1} at index {0} from Datastore.", i_statName, i_index));
return base.GetStatValue<T>(i_index, i_statName);
}
}

public class ViewFactory<T> : IViewFactory<T> where T : BaseProvider, new()
{
protected T m_viewProvider;

public IChartView GetChartView(string i_name, eChartType i_chartType, T i_provider)
{
return new ChartView<T>(i_name, i_chartType, i_provider);
}
public IGridView GetGridView(string i_name, T i_provider)
{
return new GridView<T>(i_name, i_provider);
}
public ICSVTextView GetCSVTextView(string i_name, char i_delimiter, T i_provider)
{
return new CSVTextView<T>(i_name, i_delimiter, i_provider);
}

public T ViewProvider
{
get { return m_viewProvider; }
set { m_viewProvider = value; }
}
}

public class ChartView<T> : BaseView, IChartView where T : BaseProvider
{
private eChartType m_type;

public ChartView(String _name, eChartType i_type, T i_provider)
: base(_name, i_provider)
{
m_type = i_type;
}

#region IChartView Members
public eChartType ChartType
{
get { return m_type; }
set { m_type = value; }
}

#endregion

public override void OpenView()
{
base.OpenView();
Console.WriteLine("Open ChartView: " + _name);
}

public override void CloseView()
{
Console.WriteLine("Close ChartView: " + _name);
}
}

public class GridView<T> : BaseView, IGridView where T : BaseProvider
{
public GridView(String _name, T i_provider) : base(_name, i_provider) { }
public override void OpenView()
{
base.OpenView();
Console.WriteLine("Open GridView: " + _name);
}

public override void CloseView()
{
Console.WriteLine("Close GridView: " + _name);
}
}

public class CSVTextView<T> : BaseView, ICSVTextView where T : BaseProvider
{
private readonly char m_delimiter;
public CSVTextView(String _name, char i_delimiter, T i_provider)
: base(_name, i_provider) {
m_delimiter = i_delimiter; }

#region ICSVTextView Members
public char Delimiter
{
get { return m_delimiter; }
}

#endregion
public override void OpenView()
{
base.OpenView();
Console.WriteLine("Open CSVTextView: " + _name);
}

public override void CloseView()
{
Console.WriteLine("Close CSVTextView: " + _name);
}
}

class Client<T> where T : BaseProvider, new()
{
readonly Queue<IView> _views = new Queue<IView>(4);
public void ClientMain()
{
IViewFactory<T> _factory = new ViewFactory<T>();
for (int i = 0; i < 12; i++)
{
IView _newView;
if (i % 3 == 0)
{
_newView = _factory.GetChartView("ChartView " + i, i % 2 == 0 ? eChartType.kLine : eChartType.kPie, new T());
}
else
{
if (i % 3 == 1)
{
_newView = _factory.GetGridView("GridView " + i, new T());
}
else
{
_newView = _factory.GetCSVTextView("CSV " + i, '|', new T());
}
}

_newView.RegisterStats(new List<String>(new String[] { "Stat 1", "Stat 2" }));

if (_views.Count == 4)
{
IView _view = _views.Dequeue();
_view.DeregisterStats();
_view.CloseView();
}
_views.Enqueue(_newView);
_newView.OpenView();
Thread.Sleep(2000);
}

Console.WriteLine("Opened View are: ");
{
foreach (IView view in _views)
{
Console.WriteLine(view.Name + view.GetType());
Console.WriteLine("\t Get value for each stats");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("\t\t At index" + i);
foreach (String stat in view.Stats)
{
Console.WriteLine("\t\t\t");
if (i%3 == 0)
{
Console.Write(view.ViewProvider.GetStatValue<int>(i, stat));
}
else
{
if (i%3 == 1)
{
Console.Write(view.ViewProvider.GetStatValue<string>(i, stat));
}
else
{
Console.Write(view.ViewProvider.GetStatValue<DateTime>(i, stat));
}
}
}
}
}
}
}
}

class StatisticsApp
{
static void Main()
{
new Client<RealTimeProvider>().ClientMain();
new Client<DataStoreProvider>().ClientMain();
Console.ReadLine();
}
}
}



Abstract Factory pattern is recommended when


• An application should be independent of how its products are created, composed, and represented.
• An application can be configured with one of multiple families of products.
• The constraint requiring products from the same factory to be used together must be enforced.
• The emphasis is on revealing interfaces, not implementations.

Niciun comentariu:

Trimiteți un comentariu