Sto creando un strong legame con una specifica XML e sto essenzialmente cercando di "appiattire" le specifiche il più possibile, in modo che non sembrino come se stessi manipolando un albero XML.
Ci sono molti elementi nelle specifiche XML che sono opzionali. Ecco un esempio forzato.
<person>
<name>Fred</name>
<favorite-color>Blue</favorite-color>
</person>
In questo potrebbe essere richiesto l'elemento "nome", ma l'elemento "colore preferito" potrebbe dire minOccurs = 0 in xsd rendendolo opzionale.
Ho due idee su come gestirlo, nessuna delle due sembra particolarmente elegante.
Nella versione 1 è necessario testare nullptr prima del dereferenziamento di getFavoriteColor per vedere se FavoriteColor viene utilizzato dall'oggetto Person. Questo approccio sembra un pessimo approccio perché rende incredibilmente facile bloccare il programma, soprattutto perché potrebbe essere difficile tenere traccia di quali membri sono facoltativi e quali sono richiesti. Si può finire per dover testare tutto per null tutto il tempo. Questo sembra terribile.
Nella versione 2 si può presumere che i getter non restituiranno nullptr. È necessario controllare il bool "HasFavoriteColor" per scoprire se esiste o meno FavoriteColor. Ma il compromesso è che sembra violare la regola della meno sorpresa. È possibile impostare FavoriteColor ("Blue") quindi essere sorpreso quando l'output XML non mostra Blue perché si è dimenticato di impostareHasFavoriteColor (true).
Quale di questi disegni sembra migliore, o almeno più idiomatico? C'è una soluzione migliore?
Ricerca: è simile ma non si adatta al link Questo è simile, ma ancora non sembra adattarsi Verifica della presenza di proprietà facoltative di un oggetto
Inoltre, ho scoperto che boost: opzionale esiste, ma non sembra un adattamento e non sto usando nulla tranne std e STL per il mio progetto.
(Supponiamo che "Name" e "FavoriteColor" qui sotto siano classi utente e non solo typedefs di std :: string.)
using Name = std::string;
using NamePtr = std::shared_ptr<Name>;
using FavoriteColor = std::string;
using FavoriteColorPtr = std::shared_ptr<FavoriteColor>;
/* Version 1: nullptr indicates FavoriteColor is absent,
but Name will never be null because it is required */
class Person
{
public:
Person()
:myName( std::make_shared<Name>() )
,myFavoriteColor()
{}
NamePtr getName() const { return myName; }
void setName( const NamePtr& value )
{
if( value )
{
myName = value;
}
}
FavoriteColorPtr getFavoriteColor() const { return myFavoriteColor; }
void setFavoriteColor( const FavoriteColorPtr& value ) { myFavoriteColor = value; }
private:
NamePtr myName;
FavoriteColorPtr myFavoriteColor;
};
/* Version 2: FavoriteColor and Name can both
be trusted to not be null, but you have to
check HasFavoriteColor bool to see whether
the optional data is legit */
class Person2
{
public:
Person2()
:myName( std::make_shared<Name>() )
,myFavoriteColor( std::make_shared<FavoriteColor>() )
{}
NamePtr getName() const { return myName; }
void setName( const NamePtr& value )
{
if( value )
{
myName = value;
}
}
FavoriteColorPtr getFavoriteColor() const { return myFavoriteColor; }
void setFavoriteColor( const FavoriteColorPtr& value )
{
if ( value )
{
myFavoriteColor = value;
}
}
bool getHasFavoriteColor() const { return myHasFavoriteColor; }
void setHasFavoriteColot( const bool value ) { myHasFavoriteColor = value; }
private:
NamePtr myName;
FavoriteColorPtr myFavoriteColor;
bool myHasFavoriteColor;
};