Attualmente sto lavorando a un sistema che consente agli utenti di aggiungere tag ai TagType disponibili su pagine specifiche. Ad esempio, avremmo un TagType chiamato "Installer" e l'utente vuole che il suo nome sia associato ad esso (il suo nome sarebbe il Tag).
Un requisito di questo sistema è che gli amministratori possono aggiungere vincoli a TagTypes. Una volta creato un Tag su un TagType esistente, il vincolo contenente controlla il valore del Tag.
Il nostro desiderio è di rendere il più semplice possibile implementare nuovi tipi di vincoli in futuro. Ad esempio, avremmo un vincolo di RegularExpression, un vincolo di List (il valore di un tag dovrebbe essere uno dei valori in una lista), un vincolo int-range, eccetera. Quale sarebbe il modo migliore per facilitare questa necessità? Non solo il vincolo deve essere controllato una volta creato (o modificato) un Tag, inoltre, il back-end per gli amministratori che creano nuovi vincoli deve essere regolabile in modo semplice.
Siamo arrivati a questo punto implementando qualcosa di brutto:
class TagTypeConstraint{}
class TTConstraintList : TagTypeConstraint{}
class TTConstraintIntRange : TagTypeConstraint{}
class TTConstraintRegex : TagTypeConstraint{}
Questo ha già il problema, oltre alla terribile manutenibilità, che i metodi astratti in TagTypeConstraint diventano inutili in quanto le classi ereditanti vogliono che altre informazioni siano passate ad essa (una vuole una stringa, l'altra vuole due intere, l'ultima vuole una stringa stringa di nuovo). Forse un vincolo futuro vorrà una lista di numeri interi. Penso che ci sia bisogno di un buon livello di astrazione perché il nostro back-end sia facilmente estendibile, ma come ottenerlo quando i metodi di ereditare le classi richiederanno parametri diversi?
Modifica :
Ho fatto alcuni progressi su come affrontare.
La mia classe TagTypeConstraint è ora astratta, con metodi astratti come + SetConstraint(object[] values)
e + IsValid(object[] values)
.
Questi metodi astratti vengono implementati dalle classi ereditanti e in quelle classi, le variabili oggetto [] vengono convertite in tipi appropriati. Se falliscono, lancio una ConstraintException.
Inoltre, ho aggiunto una funzione statica a TagTypeConstraint che si comporta come un (semplice) factory, eliminando la necessità di richiamare le implementazioni di TagTypeConstraint in livelli come la GUI.
Qualsiasi commento su questo sarebbe apprezzato.
Struttura corrente (aggiornata):
tag
- string _content;
- TagType _tagType;
TagType
- stringa _nome;
- TagTypeDataType _dataType;
TagTypeDataType
- stringa _nome;
- Vincolo _constint;
Vincolo astratto
- Vincolo statico CreateConstraint (tipo ConstraintType)
- abstract void SetConstraint (oggetto [] valori)
- abstract bool IsValid (oggetto [] valori)
- abstract ConstraintType GetConstraintType ()
StringListConstraint
- Elenca _constraintValues;
- ConstraintType _constraintType;
- override void SetConstraint (oggetto [] valori)
- sostituisci bool IsValid (oggetto [] valori)
- esegue l'override di ConstraintType GetConstraintType ()