bauworld title

Patterns

1 - Factory Pattern

Il Factory Pattern fornisce un’interfaccia per creare famiglie di oggetti connessi o dipendenti tra loro, in modo che non ci sia necessità da parte dei client di specificare i nomi delle classi concrete all’interno del proprio codice.
Questo pattern ha lo scopo di astrarre la costruzione di un oggetto e la sua composizione, garantendo una maggiore flessibilità e sopratutto riducendo la dipendenza della classe client, cioè quella che usa l’oggetto, dalla classe richiesta, cioè quella prodotta dal Factory Pattern.
Il pattern può rivelarsi utile quando una classe non è in grado di conoscere a priori il tipo di oggetti da creare. L’applicazione del pattern consente di eliminare le dipendenze dai tipi concreti utilizzati.
Un esempio tipico è quello della connessione ad un database. Un software, grazie all’ausilio di classi/driver (Concrete Products) potrebbe essere in grado di utilizzare un database qualsiasi.

Di seguito il diagramma UML delle classi che realizzano il Factory Pattern:

Product definisce l’interfaccia implementata da ConcreteProduct; Creator definisce il FactoryMethod che restituisce una interfaccia di tipo Product e ConcreteCreator ridefinisce il factory method per restituire ConcreteProduct.

Analisi del codice

Il programma utilizza il Factory Pattern per leggere una configurazione generica e convertirla in XML.
Come esempio sono state introdotti tre ConcreteCreator (Creator_Configuration_T1, Creator_Configuration_T2 e Creator_Configuration_T3) che implementano l'interfaccia 'IConfigurationCreator' e si occupano di instanziare una classe ConcreteProduct (Configuration_T1_Key, Configuration_T2_Key e Configuration_T3_Key), che implementa 'IConfiguration' e si occupa di leggere una configurazione di un certo tipo da uno stub restituendola in formato XML.
Per evidenziare ciò che accade c'è una form con quattro bottoni che creano differenti classi ConcreteCreator che vengono poi utilizzate dal metodo "ShowConfiguration(...)" per instanziare il ConcreteProduct e mostrare la configurazione ottenuta; nel caso del quarto bottone, la form stessa viene modificata in base alla configurazione ottenuta.

Segue un estratto dal codice della classe ConcreteCreator (Creator_Configuration_T1) che si occupa di instanziare ConcreteProduct (Configuration_T1_Key) :


using System;

namespace Factory.Classes
{
    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>
    public class Creator_Configuration_T1_Key : IConfigurationCreator
    {
        public IConfiguration FactoryConfiguration()
        {
            return new Configuration_T1_Key();
        }
    }
}


using System;

namespace Factory.Classes
{
    /// <summary>
    /// A 'Concrete Product' class
    /// </summary>
    class Configuration_T1_Key : AConfiguration
    {
        public override string LoadConfiguration(string Key, string User)
        {
            Stub_DB.GetValuesFromConfiguration(Key, User, ref ConfEnabled, ref ConfValue);
            BaseConfiguration(ref xmlConfiguration, Key, ConfEnabled, ConfValue);
            return xmlConfiguration.OuterXml;
        }
    }
}

Di seguito l'evento onclick del quarto bottone, che carica dallo stub una configurazione contenente tra l'altro delle informazioni di stile, le mostra utilizzando ShowConfiguration(...), quindi ridisegna la form in base allo stile ottenuto:



        private void ShowConfiguration(IConfiguration concreteConfiguration, string Key)
        {
            string xmlConfiguration = concreteConfiguration.LoadConfiguration(Key, "001");

            // Parse xml string
            XmlDocument xmlConfDocument = new XmlDocument();
            xmlConfDocument.LoadXml(xmlConfiguration);

            // Reading "base" tags
            if (xmlConfDocument.GetElementsByTagName("Enabled").Count > 0)
                lbEnabled.Text =
		xmlConfDocument.GetElementsByTagName("Enabled").Item(0).InnerText;
            else
                lbEnabled.Text = "***";
            if (xmlConfDocument.GetElementsByTagName("Value").Count > 0)
                lbValue_A.Text =
		xmlConfDocument.GetElementsByTagName("Value").Item(0).InnerText;
            else
                lbValue_A.Text = "***";

            // Other tags
            if (xmlConfDocument.GetElementsByTagName("Value2").Count > 0)
                lbValue_B.Text =
		xmlConfDocument.GetElementsByTagName("Value2").Item(0).InnerText;
            else
                lbValue_B.Text = "***";

            // Style tags
            if (xmlConfDocument.GetElementsByTagName("Style").Count > 0)
            {
                Control TaggedC = null;
                // Is the tagged element the form ?
                if (this.Tag != null)
                {
                    if (this.Tag.ToString().Trim() == Key)
                        TaggedC = this;
                }
                if (TaggedC == null)
                {
                    // Look for every tagged control style
                    foreach (Control C in Controls)
                    {
                        if (C.Tag != null)
                        {
                            if (C.Tag.ToString().Trim() == Key)
                            {
                                TaggedC = C;
                                break;
                            }
                        }
                    }
                }

                // Todo: class to perfom style application to control
                // Style will be parsed directly in the form object, not in the business class
                if (TaggedC != null)
                {
                    if (xmlConfDocument.GetElementsByTagName("TagVisible").Count > 0)
                        TaggedC.Visible = Convert.ToBoolean(
		xmlConfDocument.GetElementsByTagName("TagVisible").Item(0).InnerText);

                    if (xmlConfDocument.GetElementsByTagName("TagEnabled").Count > 0)
                        TaggedC.Enabled = Convert.ToBoolean(
		xmlConfDocument.GetElementsByTagName("TagEnabled").Item(0).InnerText);

                    if (xmlConfDocument.GetElementsByTagName("TagHeight").Count > 0)
                        TaggedC.Height = Convert.ToInt16(
		xmlConfDocument.GetElementsByTagName("TagHeight").Item(0).InnerText);

                    if (xmlConfDocument.GetElementsByTagName("TagWidth").Count > 0)
                        TaggedC.Width = Convert.ToInt16(
		xmlConfDocument.GetElementsByTagName("TagWidth").Item(0).InnerText);
                }
            }

            lb_ConcreteName.Text = concreteConfiguration.GetType().Name;
        }

        ...

        private void btnConfig4_Click(object sender, EventArgs e)
        {
            IConfigurationCreator configurationCreator = new Creator_Configuration_T3_Key();
            IConfiguration concreteConfiguration = configurationCreator.FactoryConfiguration();

            // Look for form style
            if (this.Tag != null)
            {
                ShowConfiguration(concreteConfiguration, this.Tag.ToString().Trim());
            }
            // Look for every tagged control style
            foreach (Control C in Controls)
            {
                if (C.Tag != null)
                {
                    ShowConfiguration(concreteConfiguration, C.Tag.ToString().Trim());
                }
            }

}

Scarica l'esempio

factory.rar