Il Factory Method, fa parte dei creational patterns, esso consente di utilizzare un'interfaccia per la creazione di un oggetto, ma sono le sottoclassi a decidere quale classe istanziare.
L’obbiettivo principale è l’estensibilità, consente di istanziare un oggetto senza specificare una classe.
Il Factory Method è spesso utilizzato in applicazioni che:
- necessitano che la creazione o la rappresentazione di oggetti sia nascosta ed indipendente dalla struttura principale.
- gestiscono, mantengono, o manipolano collezioni di oggetti diverse, ma con molte caratteristiche in comune.
- se il sistema principale viene modificato si possono modificare facilmente anche le caratteristiche comuni fra gli oggetti
- forniscono una libreria di classi in cui è visibile solo l’interfaccia, ma non l’implementazione della classe
Ci sono 3 regole principali che il pattern Factory Method deve rispettare:
- Il metodo crea un nuovo oggetto
- Il metodo ritorna una classe astratta o un interfaccia
- La classe astratta o l’interfaccia viene implementata da più classi
Ora vediamo un piccolo esempio di implementazione per capire meglio come funziona il pattern Factory Method nei seguenti linguaggi:
(questi ultimi due comunque non supportano interfacce o classi astratte, quindi bisogna prestare la massima attenzione all’implementazione, magari usando una buona convenzione sui nomi delle classi e dei metodi, in maniera di evitare di utilizzare classi o metodi sbagliati per distrazione)
Diagramma UML:
In un nuovo progetto di tipo Console aggiungo il file “Persona” e creo la classe persona (questa classe sarà usata anche nei miei prossimi post sui design patterns):
//C#
using System;
namespace Netrudy.Patterns
{
//Classe che rappresenta una persona fisica
class Persona
{
//Costruttore
public Persona(string nome, string cognome)
{
this.Nome = nome;
this.Cognome = cognome;
}
//Nome
public String Nome { get; set; }
//Cognome
public String Cognome { get; set; }
}
}
'VB.NET
Namespace Netrudy.Patterns
'Classe che rappresenta una persona fisica
Class Persona
'Costruttore
Public Sub New(nome As String, cognome As String)
Me.Nome = nome
Me.Cognome = cognome
End Sub
'Nome
Public Property Nome() As [String]
Get
Return m_Nome
End Get
Set(value As [String])
m_Nome = value
End Set
End Property
Private m_Nome As [String]
'Cognome
Public Property Cognome() As [String]
Get
Return m_Cognome
End Get
Set(value As [String])
m_Cognome = value
End Set
End Property
Private m_Cognome As [String]
End Class
End Namespace
//Java
package Netrudy.Patterns;
//Classe che rappresenta una persona fisica
public class Persona
{
//Costruttore
public Persona(String nome, String cognome)
{
this.setNome(nome);
this.setCognome(cognome);
}
//Nome
private String privateNome;
public final String getNome()
{
return privateNome;
}
public final void setNome(String value)
{
privateNome = value;
}
//Cognome
private String privateCognome;
public final String getCognome()
{
return privateCognome;
}
public final void setCognome(String value)
{
privateCognome = value;
}
}
//C++/CLI file .h
#pragma once
using namespace System;
namespace Netrudy
{
namespace Patterns
{
//Classe che rappresenta una persona fisica
private ref class Persona
{
//Costruttore
public:
Persona(String ^nome, String ^cognome);
//Nome
property String ^Nome;
//Cognome
property String ^Cognome;
};
}
}
//file .cpp
#include "Persona.h"
using namespace System;
namespace Netrudy
{
namespace Patterns
{
Persona::Persona(String ^nome, String ^cognome)
{
this->Nome = nome;
this->Cognome = cognome;
}
}
}
//C++ Nativo file .h
#pragma once
#include <string>
namespace Netrudy
{
namespace Patterns
{
//Classe che rappresenta una persona fisica
class Persona
{
//Costruttore
public:
Persona(const std::string &nome, const std::string &cognome);
//Nome
private:
std::string privateNome;
public:
std::string getNome();
void setNome(const std::string &value);
//Cognome
private:
std::string privateCognome;
public:
std::string getCognome();
void setCognome(const std::string &value);
};
}
}
//file .cpp
#include "Persona.h"
namespace Netrudy
{
namespace Patterns
{
Persona::Persona(const std::string &nome, const std::string &cognome)
{
this->Nome = nome;
this->Cognome = cognome;
}
std::string Persona::getNome()
{
return privateNome;
}
void Persona::setNome(const std::string &value)
{
privateNome = value;
}
std::string Persona::getCognome()
{
return privateCognome;
}
void Persona::setCognome(const std::string &value)
{
privateCognome = value;
}
}
}
#Python
"""Classe che rappresenta una persona fisica"""
class Persona(object):
#Costruttore
def __init__(self, nome, cognome):
self._nome = nome
self._cognome = cognome
#Nome
def getNome(self):
return self._nome
def setNome(self, value):
self._nome = value
Nome = property(getNome, setNome)
#Cognome
def getCognome(self):
return self._cognome
def setCognome(self, value):
self._cognome = value
Cognome = property(getCognome, setCognome)
//Javascript
//Classe che rappresenta una persona fisica
//Costruttore
Netrudy.Patterns._persona = function Netrudy_Patterns__persona(nome, cognome) {
this.set_nome(nome);
this.set_cognome(cognome);
}
Netrudy.Patterns._persona.prototype = {
//Nome
_nome: null,
get_nome: function Netrudy_Patterns__persona$get_nome() {
return this._nome;
},
set_nome: function Netrudy_Patterns__persona$set_nome(value) {
this._nome = value;
return value;
},
//Cognome
_cognome: null,
get_cognome: function Netrudy_Patterns__persona$get_cognome() {
return this._cognome;
},
set_cognome: function Netrudy_Patterns__persona$set_cognome(value) {
this._cognome = value;
return value;
}
}
N.B.: Per Javascript ho usato Script#:
http://projects.nikhilk.net/ScriptSharp
alcune funzioni utilizzano parte di codice della libreria “mscorlib.js” di Script#, che è un misto di AJAX e funzioni di .NET Framework riadattate al Javascript (per esempio le collezioni Enumerable).
Aggiungiamo il file “FactoryMethod” e iniziamo a scrivere il seguente codice:
Dichiaro gli oggetti dipendente e datore di lavoro che derivano da persona (e rappresentano delle persone fisiche) questi sono i nostri oggetti nascosti:
//C#
//Personale di tipo: dipendente
class ConcreteDipendente : Persona
{
public ConcreteDipendente(string nome, string cognome)
: base(nome, cognome) {}
}
//Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro : Persona
{
public ConcreteDatoreDiLavoro(string nome, string cognome)
: base(nome, cognome) {}
}
'VB.NET
'Personale di tipo: dipendente
Class ConcreteDipendente
Inherits Persona
Public Sub New(nome As String, cognome As String)
MyBase.New(nome, cognome)
End Sub
End Class
'Personale di tipo: datore di lavoro
Class ConcreteDatoreDiLavoro
Inherits Persona
Public Sub New(nome As String, cognome As String)
MyBase.New(nome, cognome)
End Sub
End Class
//Java
//Personale di tipo: datore di lavoro
public class ConcreteDatoreDiLavoro extends Persona
{
public ConcreteDatoreDiLavoro(String nome, String cognome)
{
super(nome, cognome);
}
}
//Personale di tipo: dipendente
public class ConcreteDipendente extends Persona
{
public ConcreteDipendente(String nome, String cognome)
{
super(nome, cognome);
}
}
//C++/CLI file .h
//Personale di tipo: dipendente
private ref class ConcreteDipendente : Persona
{
public:
ConcreteDipendente(String ^nome, String ^cognome);
};
//Personale di tipo: datore di lavoro
private ref class ConcreteDatoreDiLavoro : Persona
{
public:
ConcreteDatoreDiLavoro(String ^nome, String ^cognome);
};
//file .cpp
ConcreteDipendente::ConcreteDipendente(String ^nome, String ^cognome) : Persona(nome, cognome)
{
}
ConcreteDatoreDiLavoro::ConcreteDatoreDiLavoro(String ^nome, String ^cognome) : Persona(nome, cognome)
{
}
//C++ Nativo file .h
//Personale di tipo: dipendente
class ConcreteDipendente : public Persona
{
public:
ConcreteDipendente(const std::string &nome, const std::string &cognome);
};
//Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro : public Persona
{
public:
ConcreteDatoreDiLavoro(const std::string &nome, const std::string &cognome);
};
// file .cpp
ConcreteDipendente::ConcreteDipendente(const std::string &nome, const std::string &cognome) : Persona(nome, cognome)
{
}
ConcreteDatoreDiLavoro::ConcreteDatoreDiLavoro(const std::string &nome, const std::string &cognome) : Persona(nome, cognome)
{
}
#Python
#Personale di tipo: dipendente
class ConcreteDipendente(Persona):
def __init__(self, nome, cognome):
Persona.__init__(self, nome, cognome)
#Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro(Persona):
def __init__(self, nome, cognome):
Persona.__init__(self, nome, cognome)
//Javascript
//Personale di tipo: dipendente
Netrudy.Patterns._concreteDipendente = function Netrudy_Patterns__concreteDipendente(nome, cognome) {
Netrudy.Patterns._concreteDipendente.initializeBase(this, [ nome, cognome ]);
}
//Personale di tipo: datore di lavoro
Netrudy.Patterns._concreteDatoreDiLavoro = function Netrudy_Patterns__concreteDatoreDiLavoro(nome, cognome) {
Netrudy.Patterns._concreteDatoreDiLavoro.initializeBase(this, [ nome, cognome ]);
}
Come possiamo notare se c’è un costruttore nella classe base (persona) è necessario implementarlo anche nelle classi derivate.
Queste due classi appena create sono quelle concrete, cioè quelle con i campi e i metodi delle persone, e verranno create o meno a seconda di cosa scriveremo nel metodo di creazione FactoryMethod che implementeremo derivando la nostra nuova classe dalla seguente classe astratta:
//C#
//Classe astratta che rappresenta il personale dell'azienda
abstract class PersonaleAziendaCreator
{
//Costruttore che chiama il metodo astratto
//FactoryMethod
//che verrà implementato nella classe figlia
protected PersonaleAziendaCreator()
{
Persone = new List();
this.FactoryMethod();
}
//Metodo astratto da implementare
protected abstract void FactoryMethod();
//Lista del personale aziendale (che sarà legato
//alla categoria della classe figlia)
public List Persone { get; protected set; }
}
'VB.NET
'Classe astratta che rappresenta il personale dell'azienda
MustInherit Class PersonaleAziendaCreator
'Costruttore che chiama il metodo astratto FactoryMethod
'che verrà implementato nella classe figlia
Protected Sub New()
Persone = New List(Of Persona)()
Me.FactoryMethod()
End Sub
'Metodo astratto da implementare
Protected MustOverride Sub FactoryMethod()
'Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
Public Property Persone() As List(Of Persona)
Get
Return m_Persone
End Get
Protected Set(value As List(Of Persona))
m_Persone = Value
End Set
End Property
Private m_Persone As List(Of Persona)
End Class
//Java
//Classe astratta che rappresenta il personale dell'azienda
public abstract class PersonaleAziendaCreator
{
//Costruttore che chiama il metodo astratto FactoryMethod
//che verrà implementato nella classe figlia
protected PersonaleAziendaCreator()
{
setPersone(new java.util.ArrayList<Persona>());
this.FactoryMethod();
}
//Metodo astratto da implementare
protected abstract void FactoryMethod();
//Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
private java.util.ArrayList<Persona> privatePersone;
public final java.util.ArrayList<Persona> getPersone()
{
return privatePersone;
}
protected final void setPersone(java.util.ArrayList<Persona> value)
{
privatePersone = value;
}
}
//C++/CLI file .h
//Classe astratta che rappresenta il personale dell'azienda
private ref class PersonaleAziendaCreator abstract
{
//Costruttore che chiama il metodo astratto FactoryMethod
//che verrà implementato nella classe figlia
protected:
PersonaleAziendaCreator();
//Metodo astratto da implementare
virtual void FactoryMethod() abstract;
//Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
public:
property List<Persona^> ^Persone;
};
//file .cpp
PersonaleAziendaCreator::PersonaleAziendaCreator()
{
Persone = gcnew List<Persona^>();
this->FactoryMethod();
}
//C++ Nativo file .h
//Classe astratta che rappresenta il personale dell'azienda
class PersonaleAziendaCreator
{
//Costruttore che chiama il metodo astratto FactoryMethod
//che verrà implementato nella classe figlia
protected:
PersonaleAziendaCreator();
//Metodo astratto da implementare
virtual void FactoryMethod() = 0;
//Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
private:
std::vector<Persona*> privatePersone;
public:
std::vector<Persona*> getPersone();
void setPersone(std::vector<Persona*> value);
};
//file .cpp
PersonaleAziendaCreator::PersonaleAziendaCreator()
{
Persone = std::vector<Persona*>();
this->FactoryMethod();
}
std::vector<Persona*> PersonaleAziendaCreator::getPersone()
{
return privatePersone;
}
void PersonaleAziendaCreator::setPersone(std::vector<Persona*> value)
{
privatePersone = value;
}
#Python
"""Classe astratta che rappresenta il personale dell'azienda"""
#Python non supporta interfacce o classi astratte quindi utilizziamo il seguente workaround
class PersonaleAziendaCreator(object):
def __init__(self):
self._persone = []
self.FactoryMethod()
#workaround per metodo astratto
def FactoryMethod(self, arg):
raise NotImplementedError("Metodo astratto!")
def getPersone(self):
return self._persone
def setPersone(self, value):
self._persone = value
Persone = property(getPersone, setPersone)
//Javascript
//Classe che rappresenta il personale dell'azienda
Netrudy.Patterns._personaleAziendaCreator = function Netrudy_Patterns__personaleAziendaCreator() {
this.set_persone([]);
//Metodo astratto da implementare
this.factoryMethod();
}
Netrudy.Patterns._personaleAziendaCreator.prototype = {
_persone: null,
//Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
get_persone: function Netrudy_Patterns__personaleAziendaCreator$get_persone() {
return this._persone;
},
set_persone: function Netrudy_Patterns__personaleAziendaCreator$set_persone(value) {
this._persone = value;
return value;
}
}
Ora creiamo le classi di creazione del personale dell’azienda che implementeranno il FactoryMethod poiché derivando dalla classe base PersonaleAziendaCreator:
//C#
//Classe che si occupa di creare i dipendenti
//dell'azienda
class ConcreteCreatorDipendente : PersonaleAziendaCreator
{
protected override void FactoryMethod()
{
Persone.Add(new ConcreteDipendente("Luigi", "Bross"));
Persone.Add(new ConcreteDipendente("Toad", "Fungo"));
}
}
//Classe che si occupa di creare i datori di lavoro
//dell'azienda
class ConcreteCreatorDatoreDiLavoro : PersonaleAziendaCreator
{
protected override void FactoryMethod()
{
Persone.Add(new ConcreteDatoreDiLavoro("Mario", "Boss"));
}
}
'VB.NET
'Classe che si occupa di creare i dipendenti dell'azienda
Class ConcreteCreatorDipendente
Inherits PersonaleAziendaCreator
Protected Overrides Sub FactoryMethod()
Persone.Add(New ConcreteDipendente("Luigi", "Bross"))
Persone.Add(New ConcreteDipendente("Toad", "Fungo"))
End Sub
End Class
'Classe che si occupa di creare i datori di lavoro dell'azienda
Class ConcreteCreatorDatoreDiLavoro
Inherits PersonaleAziendaCreator
Protected Overrides Sub FactoryMethod()
Persone.Add(New ConcreteDatoreDiLavoro("Mario", "Boss"))
End Sub
End Class
//Java
//Classe che si occupa di creare i dipendenti dell'azienda
public class ConcreteCreatorDipendente extends PersonaleAziendaCreator
{
@Override
protected void FactoryMethod()
{
getPersone().add(new ConcreteDipendente("Luigi", "Bross"));
getPersone().add(new ConcreteDipendente("Toad", "Fungo"));
}
}
//Personale di tipo: datore di lavoro
public class ConcreteDatoreDiLavoro extends Persona
{
public ConcreteDatoreDiLavoro(String nome, String cognome)
{
super(nome, cognome);
}
}
//C++/CLI file .h
//Classe che si occupa di creare i dipendenti dell'azienda
private ref class ConcreteCreatorDipendente : PersonaleAziendaCreator
{
protected:
virtual void FactoryMethod() override;
};
//Classe che si occupa di creare i datori di lavoro dell'azienda
private ref class ConcreteCreatorDatoreDiLavoro : PersonaleAziendaCreator
{
protected:
virtual void FactoryMethod() override;
};
//file .cpp
void ConcreteCreatorDipendente::FactoryMethod()
{
Persone->Add(gcnew ConcreteDipendente("Luigi", "Bross"));
Persone->Add(gcnew ConcreteDipendente("Toad", "Fungo"));
}
void ConcreteCreatorDatoreDiLavoro::FactoryMethod()
{
Persone->Add(gcnew ConcreteDatoreDiLavoro("Mario", "Boss"));
}
//C++ Nativo file .h
//Classe che si occupa di creare i dipendenti dell'azienda
class ConcreteCreatorDipendente : public PersonaleAziendaCreator
{
protected:
virtual void FactoryMethod();
};
//Classe che si occupa di creare i datori di lavoro dell'azienda
class ConcreteCreatorDatoreDiLavoro : public PersonaleAziendaCreator
{
protected:
virtual void FactoryMethod();
};
//file .cpp
void ConcreteCreatorDipendente::FactoryMethod()
{
Persone->Add(new ConcreteDipendente("Luigi", "Bross"));
Persone->Add(new ConcreteDipendente("Toad", "Fungo"));
}
void ConcreteCreatorDatoreDiLavoro::FactoryMethod()
{
Persone->Add(new ConcreteDatoreDiLavoro("Mario", "Boss"));
}
#Python
#Classe che si occupa di creare i dipendenti dell'azienda
class ConcreteCreatorDipendente(PersonaleAziendaCreator):
def FactoryMethod(self):
self.Persone.append(ConcreteDipendente("Luigi", "Bross"))
self.Persone.append(ConcreteDipendente("Toad", "Fungo"))
#Classe che si occupa di creare i datori di lavoro dell'azienda
class ConcreteCreatorDatoreDiLavoro(PersonaleAziendaCreator):
def FactoryMethod(self):
self.Persone.append(ConcreteDatoreDiLavoro("Mario", "Boss"))
//Javascript
//Classe che si occupa di creare i dipendenti dell'azienda
Netrudy.Patterns._concreteCreatorDipendente = function Netrudy_Patterns__concreteCreatorDipendente() {
Netrudy.Patterns._concreteCreatorDipendente.initializeBase(this);
}
Netrudy.Patterns._concreteCreatorDipendente.prototype = {
factoryMethod: function Netrudy_Patterns__concreteCreatorDipendente$factoryMethod() {
this.get_persone().add(new Netrudy.Patterns._concreteDipendente('Luigi', 'Bross'));
this.get_persone().add(new Netrudy.Patterns._concreteDipendente('Toad', 'Fungo'));
}
}
//Classe che si occupa di creare i datori di lavoro dell'azienda
Netrudy.Patterns._concreteCreatorDatoreDiLavoro = function Netrudy_Patterns__concreteCreatorDatoreDiLavoro() {
Netrudy.Patterns._concreteCreatorDatoreDiLavoro.initializeBase(this);
}
Netrudy.Patterns._concreteCreatorDatoreDiLavoro.prototype = {
factoryMethod: function Netrudy_Patterns__concreteCreatorDatoreDiLavoro$factoryMethod() {
this.get_persone().add(new Netrudy.Patterns._concreteDatoreDiLavoro('Mario', 'Boss'));
}
}
A questo punto proviamo il programma implementando il metodo main del nostro progetto:
//C#
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator creaDatori = new ConcreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
List persone = new List(creaDatori.Persone.Union(creaDipendenti.Persone));
//Per ogni persona scrive a video il tipo di oggetto
//della persona e il nome
foreach (Persona persona in persone)
{
Console.WriteLine("Persona (di tipo: {0}): {1}", persona.GetType(), persona.Nome);
}
'VB.NET
'Istanzio la classe per creare i dipendenti
Dim creaDipendenti As PersonaleAziendaCreator = New ConcreteCreatorDipendente()
'Istanzio la classe per creare i datori di lavoro
Dim creaDatori As PersonaleAziendaCreator = New ConcreteCreatorDatoreDiLavoro()
'Unisco il gruppo di persone create
Dim persone As New List(Of Persona)(creaDatori.Persone.Union(creaDipendenti.Persone))
'Per ogni persona scrive a video il tipo di oggetto della persona e il nome
For Each persona As Persona In persone
Console.WriteLine("Persona (di tipo: {0}): {1}", persona.[GetType](), persona.Nome)
Next
//Java
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator creaDatori = new ConcreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
java.util.ArrayList<Persona> persone = new java.util.ArrayList<Persona>(creaDatori.getPersone().Union(creaDipendenti.getPersone()));
//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for (Persona persona : persone)
{
System.out.println("Persona (di tipo: {0}): {1}", persona.getClass(), persona.getNome());
}
//C++/CLI file .cpp
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator ^creaDipendenti = gcnew ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator ^creaDatori = gcnew ConcreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
List<Persona^> ^persone = gcnew List<Persona^>(creaDatori->Persone->Union(creaDipendenti->Persone));
//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for each (Persona ^persona in persone)
{
Console::WriteLine("Persona (di tipo: {0}): {1}", persona->GetType(), persona->Nome);
}
//C++ Nativo .cpp
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator *creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator *creaDatori = new ConcreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
std::vector<Persona*> persone = std::vector<Persona*>(creaDatori->Persone->Union(creaDipendenti->Persone));
//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for (std::vector<Persona*>::const_iterator persona = persone.begin(); persona != persone.end(); ++persona)
{
std::cout << "Persona (di tipo: " << (*persona)->GetType() << "): " << (*persona)->Nome << std::endl;
}
#Python
#Istanzio la classe per creare i dipendenti
creaDipendenti = ConcreteCreatorDipendente()
#Istanzio la classe per creare i i datori di lavoro
creaDatori = ConcreteCreatorDatoreDiLavoro()
#Unisco il gruppo di persone create
persone = list(set(creaDipendenti.getPersone()) | set(creaDatori.getPersone()))
#Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for persona in persone:
print "Persona (di tipo: {0})): {1}".format(type(persona), persona.Nome)
//Javascript
//Istanzio la classe per creare i dipendenti
var creaDipendenti = new Netrudy.Patterns._concreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
var creaDatori = new Netrudy.Patterns._concreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
var persone = creaDipendenti.get_persone().concat(creaDatori.get_persone());
//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
var $enum1 = ss.IEnumerator.getEnumerator(persone);
while ($enum1.moveNext()) {
var persona = $enum1.current;
ss.Debug.writeln(String.format('Persona (di tipo: {0}): {1}', Type.getInstanceType(persona), persona.get_nome()));
}