Теперь займемся разработкой
класса который будет отвечать за создание экземпляров интерфейса IPainter в
зависимости от переданных данных.
Еще раз посмотрим на
струкутру XML файла который описывает графические примитивы. Любой объект
описывается как
<object type=[тип]>
<[имя свойства]>[значение свойства]</[имя свойства]>
<[имя свойства]>[значение свойства]</[имя свойства]>
……
</object>
Нетрудно заметить что любая графическая примитива описывается набором пар имя-значение. В пространстве System.Collections.Specialized имеется достаточно много классов которые могут быть иползованы для такого набора данных. Так как данные хранятся в XML файле, выберем класс NameValueCollection, экземпляры этого класса будут описывать графические примитивы.
Итак, задача класса-фабрики создать экземпляр интерфейса IPainter основываясь на описании объекта NameValueCollection. Посмотрим на код:
/// <summary>
/// Represents Factory that responsible for <see cref="IPainter"/> implementation creation.
/// </summary>
public
class PaintFactory
{
/// <summary>
/// Create implementation of <see cref="IPainter"/> interface.
/// </summary>
/// <param
name="description">Parameters of
graphic primitive.</param>
/// <returns>implementation of <see
cref="IPainter"/> interface.</returns>
/// <exception
cref="ArgumentException">Throws
if grphics primitive has invalid parameters.</exception>
public IPainter GetPainter(NameValueCollection description)
{
IPainter painter=null;
switch(description["type"])
{
case "Circle": int
centerX=int.Parse(description["centerX"],CultureInf
int
centerY=int.Parse(description["centerY"],CultureInf
int
radius=int.Parse(description["radius"],CultureInfo.I
Color
color=GetColorFromString(description["co
painter=new Circle(centerX,centerY,radius,color);
break;
case "Rectangle": int x=int.Parse(description["x1"],CultureInfo.Inv
int y=int.Parse(description["y1"],CultureInfo.Inv
int height=int.Parse(description["Height"],CultureInfo.I
int
width=int.Parse(description["Width"],CultureInfo.I
color=GetColorFromString(description["co
painter=new
Rectangle(x,y,width,height,color);
break;
default: throw new ArgumentException("Invalid data
structure");
}
return painter;
}
private Color GetColorFromString(string
s)
{
string [] c=s.Split(new
char[]{','});
int r=int.Parse(c[0],CultureInfo.InvariantCulture)
int g=int.Parse(c[1],CultureInfo.InvariantCulture)
int b=int.Parse(c[2],CultureInfo.InvariantCulture)
Color
color=Color.FromArgb(r,g,b);
return color;
}
}
Все выглядит достаточно
прозрачно, и, я думаю, в пояснениях не нуждается.
Отступление: Класс PaintFactory добавим в сборку Samples.Patterns.SimpleFactorySample.Primitives это единственный класс видный клиентскому приложению(модификатор
класса установлен в public).
Осталось написать код
для клиентского приложения. Он тоже будет достаточно простым:
public class Painter
{
private string _filename;
private Graphics _graphics;
private
XmlDocument _document=null;
private XmlElement _root=null;
/// <summary>
/// Initializes new instance of <see cref="Painter"/> class.
/// </summary>
/// <param
name="filename">FileName of XML
datasource that contains description of objects.</param>
/// <param
name="graphics">Drawing surface
to draw objects.</param>
public Painter(string
filename,Graphics graphics)
{
this._filename=filename;
this._graphics=graphics;
//Read XML file, initialize _document and _root private
fields.
}
/// <summary>
/// Draws graphics objects that are
described in the XML datasource.
/// </summary>
public void Draw()
{
PaintFactory
factory=new PaintFactory();
foreach(XmlNode o in this._root.ChildNodes)
{
NameValueCollection
primitive=GetParameters(o);
IPainter
painter=factory.GetPainter(primitive);
painter.Draw(this._graphics);
}
}
private
NameValueCollection GetParameters(XmlNode node)
{
NameValueCollection parameters=new
NameValueCollection();
parameters.Add("type",node.Attributes["t
foreach(XmlNode p in
node.ChildNodes)
{
parameters.Add(p.Name,
p.InnerText);
}
}
}
Клиенсткое приложение вообще
ничего не знает о том как устроена та или иная графическая примитива, какие
параметры необходимы для ее создания. Приложение выполняет свою основную задачу:
Приложение должно
считывать данные из XML файла и
отображать описанные примитивы на заданной поверхности(используя класс Graphics).
Итак, мы написали простое и легко расширяемое приложения
испольую метод Примитивная Фабрика
Объектов. Если вдруг появятся другие возможные графические примитивы, мы
просто добавим несколько строк кода в сборку Samples.Patterns.SimpleFactorySample.Primitives и
клиентское приложение не будет нуждаться в перекомпилировании.
Далее
будет преведно еще несколько примеров использования метода Примитивная Фабрика Объектов.
Буквально на днях заработало приложение Планировщик Заданий, типа винодового scheduled tasks в котором я успешно применил этот «паттерн проектирования».
August 22 2005, 12:42:01 UTC 6 years ago
October 3 2005, 16:41:17 UTC 6 years ago