Quale struttura di classe consente una classe base e un mix / match di sottoclassi? (Simile agli utenti con ruoli)

4

Ho un set di caratteristiche di base e quindi un numero di sottotipi. Ogni istanza deve essere uno dei sottotipi, ma può essere più sottotipi contemporaneamente. I sottotipi di ogni cosa possono cambiare. In generale, non mi interessa quale sottotipo ho, ma a volte mi interessa.

Questo è molto simile al tipo di relazione Utenti-Ruoli in cui un utente con un ruolo particolare conferisce all'utente caratteristiche aggiuntive. Una sorta di digitazione anatra (cioè se il mio Foo ha un Bar , posso trattarlo come un ThingWithABar .)

L'ereditarietà diretta non funziona, dal momento che non consente il mix / match di sottotipi. (cioè senza multi-ereditarietà).

La composizione diritta non funziona perché non posso riattivarlo in fase di runtime.

Come posso modellarlo?

    
posta cdeszaq 02.04.2012 - 22:41
fonte

3 risposte

4

Quello che vuoi sono Interfacce.

Ogni interfaccia può richiedere una caratteristica. Una classe può implementare più interfacce a piacimento:

interface Foo {
  boolean doFoo();
}

interface Bar {
  boolean doBar();
}

class fooImpl implements Foo {
  boolean doFoo(){
    . . .
  }

}

class barImpl implements Bar {
  boolean doBar(){
    . . .
  }

}

class fooBarImpl implements Foo, Bar {
  boolean doFoo(){
    . . .
  }
  boolean doBar(){
    . . .
  }
}

Aggiorna

In alternativa, implementa il modello di stato . Uno stato sarebbe HasABar e fornirebbe il comportamento desiderato per quando il tuo Foo ha una barra. Un altro stato potrebbe essere HasABat, che fornisce un comportamento diverso. Il tuo oggetto Foo può iniziare con HasNothing, finché non gli dai una barra, che cambierebbe lo stato in HasABar.

interface FooState {
   Drink getDrink() throws InvalidStateException;
}

class HasNothing implements FooState {
   Foo foo;

   HasNothing(Foo foo) {
      this.foo = foo;
   }   

   Drink getDrink() throws InvalidStateException {
      throw new InvalidStateException("There's no Bar");
   }
}

class HasABar implements FooState {
   Foo foo;

   HasABar(Foo foo) {
      this.foo = foo;
   }   
   Drink getDrink() throws InvalidStateException{
      Foo foo.getBar().getDrink();
   }
}

class Foo {
   FooState state;
   Bar bar;

   public Foo() {
      state = new HasNothing(this);
  }

   Bar getBar() {
      return bar;
   }

   void setBar(Bar bar) {
      this.Bar = bar;
      if (null != bar) {
         state = new HasABar(this);
      }
      else {
         state = new HasNothing(this);
      }
   }

   Drink getDrink() throws InvalidStateException{
         return state.getDrink();
   }
}

A questo punto non ti occupi veramente di sottotipi, hai un tipo che si comporta in modo diverso a seconda dello stato durante il runtime.

    
risposta data 02.04.2012 - 23:33
fonte
1

Inizia con la tua classe principale, Utente. Quindi includi un elenco di oggetti, chiamali Istanze o implementazioni del ruolo. Il tuo ruolo deve assomigliare completamente all'Utente in modo che possa parlare con loro, ma le loro implementazioni possono essere molto diverse. (E in effetti possono avere poteri (metodi) di cui l'Utente non sa nulla.Ognuno deve essere Ruolo, qualunque altra cosa possa essere.) Essenzialmente, quando l'Utente è chiamato a fare qualcosa che non può fare da solo, direttamente, lo farà passare attraverso la lista chiedendo ogni ruolo se può farlo. Quando ne trova uno che può, chiama quel metodo doIt del ruolo. E puoi scambiare le istanze di ruolo dentro e fuori l'utente in qualsiasi momento.

L'utente potrebbe voler passare un'istanza di Role a un chiamante, perché il chiamante potrebbe sapere che un ruolo con un ID di 6 implementa l'interfaccia di DatabaseReader e ha metodi di cui l'oggetto Utente non sa nulla.

Non sono sicuro di cosa hai bisogno, ma spero che questo ti dia qualche idea, anche se non risolve il tuo problema.

    
risposta data 03.04.2012 - 19:03
fonte
-2

Un modo per farlo è una tabella di mapping in un database per mappare gli utenti alle autorizzazioni consentite e creare una funzione db per controllare le autorizzazioni e aggiungerla all'inizio di qualsiasi richiesta db che richiede permessi. Ciò consente la modifica del tempo di esecuzione di ruoli e autorizzazioni arbitrarie per ciascun utente.

    
risposta data 02.04.2012 - 22:55
fonte

Leggi altre domande sui tag