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,
| 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