Esempi di API Java che richiedono una sequenza di azioni

7

Come parte di una ricerca su cui sto lavorando, sto cercando API pubbliche che funzionino correttamente solo quando applichi una determinata sequenza di azioni su di esse.

Ad esempio, la classe java.nio.channels.SocketChannel , dalla libreria standard Java, funziona solo correttamente con sequenze come open() -> connect() -> read() -> read() -> close() . Una dimostrazione più completa se il modo in cui può essere utilizzato può essere rappresentato nel seguente grafico:

UlterioriesempidiAPIdellalibreriastandardJavacherichiedonodeterminatesequenzesono java.io.PrintStream (molto simile a quello sopra) e java.util.Iterator (che richiede una chiamata di next() tra ogni due% chiamate diremove(), quindi impone una determinata sequenza).

Quindi, le API preferite per fare X si comportano in questo modo? Mi piacerebbe molto conoscere le API aggiuntive che richiedono una determinata sequenza di metodi per un utilizzo corretto ; specialmente le classi che non fanno parte della libreria standard Java. Più complessa è la sequenza (s) richiesta, meglio è.

Alcune API richiedono una sequenza che si estende su più classi, ad esempio:

X x = new X();
x.setup();
Y y = x.createNewY();
Z z = new Z(y);
z.doSomething();

Questi esempi sono anche interessanti, ma sono principalmente alla ricerca di sequenze che appaiono tutte nella stessa classe.

EDIT ha aggiunto bounty per una maggiore visibilità. Sono sicuro che molti di voi hanno incontrato molte API che corrisponderanno a questa descrizione: apprezzerei davvero alcuni buoni esempi.

    
posta Oak 25.11.2010 - 17:17
fonte

8 risposte

5

Dal framework Spring

L' interfaccia del ciclo di vita impone la seguente azione sequenza:

start (isRunning)* stop

che è usato in quasi tutti i componenti principali che compongono il framework. Fortunatamente, questo ciclo di vita è gestito dal contenitore.

Dal framework Hibernate

L'interfaccia Lifecycle supporta la seguente sequenza di azioni:

(onDelete, onSave, onUpdate)* onLoad

Dall'API servlet

Il mio preferito di tutti i tempi - il ciclo di vita di un servlet :

init service destroy

con servizio che delega a doGet, operazioni doPost ecc.

    
risposta data 30.11.2010 - 01:01
fonte
3

Forse sto fraintendendo, ma sarebbe il seguente adattamento?

  • java.lang.Thread

    deve chiamare thread.start() prima di thread.stop()

  • InputStream e OutputStream

    non deve chiamare altri metodi dopo aver chiamato close()

risposta data 29.11.2010 - 00:36
fonte
3

java.sql.ResultSet

contiene operazioni che richiedono un certo ordine:

sposta i comandi ( absolute(int row) o next() ),

comandi di lettura / scrittura ( getInt(int columnIndex) o updateInt(int columnIndex, int x) ),

comandi write-back-to-datasource ( updateRow() ),

comandi di rilascio ( close() ).

    
risposta data 29.11.2010 - 09:43
fonte
2

Una "best practice" imminente per gestire questo problema nella fase di inizializzazione degli oggetti in Java, consiste nell'utilizzare un modello Builder che ha un cosiddetto builder su cui sono stati eseguiti i passaggi, quindi viene creato un oggetto. Se i passaggi non sono validi, il builder fallisce.

Da link :

Widget z = new Widget.Builder("3", 4.0).
                     manufacturer("333").
                     serialNumber("54321").build();

Il Builder è una classe nidificata per Widget, che quindi ha metodi chiamati (restituendo lo stesso oggetto builder di nuovo) fino a quando viene chiamato il metodo build (), che crea e restituisce il Widget necessario.

Può ridurre la complessità un po '.

    
risposta data 28.11.2010 - 22:28
fonte
2

Che dire di java.util.Calendar? Non richiede una sequenza di azioni complated, ma è un vero PITA per il numero di volte che devi usarlo:

//1. get a new instance
Calendar cal=Calendar.getInstance();
//2. set the different fields
cal.set(Calendar.DATE, 12);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.YEAR, 1982);
//3. use it, for whatever
Date d=cal.getTime();

E, per non parlare dell'API Java Transaction, quando Bean è gestito:

@Stateless
@TransactionManagement(BEAN)
public class ExampleBean {

    @Resource
    private SessionContext ctx;

    public void foo() {
        UserTransaction utx = ctx.getUserTransaction();

        // start a transaction
        utx.begin();

        // Do work

        // Commit it
        utx.commit();
    }
}

Il marshalling JAXB

//1. get context
JAXBContext jc = JAXBContext.newInstance( Foo.class );
//2. create Marshaller instance
Marshaller m = jc.createMarshaller();
//3. set properties
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
  Boolean.TRUE);
//at last, marshall
m.marshal( foo, System.out );

e unmarshalling:

//1. get context
JAXBContext jc = JAXBContext.newInstance( Foo.class );
//2. create Unmarshaller instance
Unmarshaller u = jc.createUnmarshaller();
//3. optional: set properties, format validation, schema validation, etc
u.setValidating( true );
//4. unmarshall
Foo foo = (PurchaseOrder)u.unmarshal(
       new FileInputStream( "po.xml" ) );
    
risposta data 30.11.2010 - 16:51
fonte
1

Il documento accademico " ESP: verifica del programma sensibile al percorso in tempo polinomiale " include esempi di apertura e chiudere i file, oltre a verificare le chiamate a fprintf. E il concetto funziona con gli FSM generali, e questo potrebbe essere più vicino a quello che stai cercando.

Il vantaggio è che il sistema ESP verifica che in realtà obbedisci a queste regole. Anche collegato a questa linea di ricerca è BLAST .

Se desideri requisiti più espliciti nel linguaggio di programmazione, consulta il tipo sensibile al flusso di Foster Qualificazioni . Quale può essere utile, ad esempio, per verificare che una stringa "contaminata" sia stata pulita prima di essere utilizzata in una query SQL.

A seconda della natura del tuo progetto, dovresti esaminare il classico push prima di peek o pop su uno stack. Non sono sicuro di quanto bene gli approcci di cui sopra possano gestire quel caso, perché il conteggio del numero di chiamate effettuate è importante.

    
risposta data 28.11.2010 - 18:48
fonte
1

Il C ++ STL ha una varietà di regole su quando gli iteratori sono invalidati. Ad esempio, l'aggiunta di un elemento a un vettore potrebbe invalidare tutti gli iteratori in quel vettore.

Qualsiasi libreria contenitore deve contenere casi speciali per contenitori vuoti.

Mi sono occupato di una API di database, IBPP, ha richiesto una chiamata a > Start () all'oggetto transazione, prima di creare qualsiasi istruzione associata alla transazione. Alla fine chiamerai - > Commit (); (o - > Rollback () se le cose non sono andate bene) Altre API sono simili, ma probabilmente un po 'più complesse a causa di problemi come l'autocommit.

Mi sono certamente occupato del codice interno che ha funzionato in questo modo. Tuttavia, ho considerato un bug.

Il modulo pygame in python richiede quella chiamata .init () e poi .display.set_mode () per impostare una modalità grafica.

Tutto ciò a cui riesco a pensare ha versioni relativamente banali di questo. Non riesco a pensare a casi che abbiano una versione davvero complessa come te.

    
risposta data 29.11.2010 - 02:22
fonte
0

Come analizzare un documento XML?

DocumentBuilderFactory dbf = DocumentBuilderFactory.getInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("file.xml"));
    
risposta data 30.11.2010 - 19:54
fonte

Leggi altre domande sui tag