Un wrapper (dal verbo inglese to wrap, "avvolgere") o funzione wrapper (in italiano talvolta definita funzione-involucro o funzione di confezionamento), in informatica e in particolare nella programmazione software, è un modulo o una funzione il cui scopo principale consiste nel fungere da tramite chiamando un secondo sottoprogramma, una classe o una chiamata di sistema, eseguendo al contempo poche o nessuna elaborazione aggiuntiva.

A differenza di una generica funzione, un wrapper opera come delegato, "rivestendo" il componente software originale in modo che i client interagiscano esclusivamente con l'interfaccia esposta dal wrapper stesso, mentre l'effettiva esecuzione del servizio viene demandata al modulo sottostante. Questo principio di astrazione e delega può essere applicato a singoli sottoprogrammi (come funzioni e metodi) oppure a interi tipi di dati, classi, oggetti e librerie software.

Scopi principali e utilizzo

Praticità di programmazione e manutenibilità L'uso dei wrapper semplifica la scrittura di programmi e migliora il disaccoppiamento del codice, in particolare quando si integrano librerie di terze parti. Creando una funzione wrapper per ciascuna delle funzioni fornite dalla libreria esterna, l'applicazione nativa interagirà solo con i wrapper. Qualora la libreria di terze parti venga aggiornata o modificata (ad esempio, con cambi di firma o di parametri nelle sue funzioni), lo sviluppatore dovrà modificare unicamente i wrapper interni, senza dover rintracciare e correggere ogni singola istanza nel codice dell'applicazione. Un esempio di questa astrazione è rappresentato dalle classi di tipo MouseAdapter nella libreria Java AWT.

Adattamento delle interfacce (Adapter pattern) I wrapper consentono di convertire l'interfaccia di una classe o di un oggetto esistente in un'altra interfaccia attesa dai client, garantendo la compatibilità tra componenti altrimenti non integrabili. Questo concetto si ricollega direttamente al design pattern strutturale noto come Adapter (lett. adattatore).

Test del codice e gestione centralizzata degli errori Scrivere controlli di errore e procedure di verifica per ogni singola chiamata a funzioni di sistema può appesantire notevolmente la lettura del codice. Sostituendo le chiamate dirette con chiamate a una funzione wrapper, i controlli di sicurezza e la gestione delle eccezioni possono essere scritti una sola volta all'interno del wrapper stesso, sollevando il programmatore dal ripeterli nel flusso principale del programma.

Test driver: È un tipo speciale di wrapper utilizzato per sottoporre a test rigorosi un modulo di codice, richiamandolo ripetutamente con parametri e configurazioni differenti per verificare ogni possibile percorso logico (molto comune nei test di regressione). Adattatore di interfaccia: Un wrapper che semplifica, adatta o amplia l'interfaccia di un modulo (ad esempio rinominando parametri, combinandoli o impostando valori predefiniti) per renderla più chiara all'utente.

Simulazione dell'ereditarietà multipla Nei linguaggi di programmazione che non supportano l'ereditarietà multipla delle classi (come Java), i wrapper e il meccanismo della delega permettono di simularne il comportamento. Una classe può implementare più interfacce contemporaneamente e delegare l'effettiva esecuzione dei metodi a istanze interne di classi diverse, avvolgendole.

Astrazione di chiamate di sistema e funzioni di libreria Molte funzioni presenti nelle librerie standard, come la Libreria standard del C (ad esempio all'interno di glibc), agiscono come interfacce e wrapper per le chiamate di sistema (system call) di basso livello del sistema operativo. Funzioni come fork ed execve in glibc chiamano internamente le rispettive e omonime chiamate di sistema del kernel, semplificando l'interazione per il programmatore.

Funzioni di supporto (Helper functions) Una funzione di supporto (helper function) è un tipo di wrapper che raggruppa parti di un calcolo o operazioni frequenti assegnando loro nomi descrittivi e facilitandone il riutilizzo. Sebbene non tutti i wrapper siano funzioni di supporto, tutte le funzioni di supporto sono strutturalmente dei wrapper. Esse trovano largo impiego, ad esempio, nella traduzione binaria dinamica per convertire le istruzioni da un set di architettura a un altro.

Interoperabilità tra linguaggi (Language Binding) I wrapper facilitano l'interoperabilità e il riutilizzo del codice in ambienti software eterogenei. Strumenti come SWIG (Simplified Wrapper and Interface Generator) o GNU Guile consentono di generare automaticamente wrapper per collegare e utilizzare librerie scritte in un linguaggio (come C o C++) all'interno di altri linguaggi di programmazione, risolvendo i problemi di binding.

Esempio di codice Il seguente esempio in linguaggio Java mostra come una classe (StackSet) possa simulare l'ereditarietà multipla implementando due interfacce diverse (Stack e Set). La classe agisce come un wrapper, delegando internamente l'effettiva logica e memorizzazione dei dati a due oggetti standard della libreria Java (LinkedList e HashSet): import java.util.HashSet; import java.util.LinkedList;

// Definizione dell'interfaccia Stack interface Stack { boolean push(Object o); Object pop(); }

// Definizione dell'interfaccia Set interface Set { boolean contains(Object o); }

// Classe wrapper che implementa entrambe le interfacce simulando l'ereditarietà multipla public class StackSet implements Stack, Set {

// Componenti interni "avvolti" dal wrapper private LinkedList stack = new LinkedList(); private HashSet set = new HashSet();

// Metodo wrapper che delega l'operazione di push a HashSet e LinkedList @Override public boolean push(Object o) { if (set.add(o)) { return stack.push(o); // Delega alla struttura LinkedList sottostante } else { return false;

// Metodo wrapper che delega la rimozione dell'elemento @Override public Object pop() { Object o = stack.pop(); // Delega a LinkedList set.remove(o); // Delega a HashSet return o;

// Metodo wrapper che delega la verifica di presenza del dato @Override public boolean contains(Object o) { return set.contains(o); // Delega a HashSet

Note e riferimenti bibliografici

Bob Reselman, Richard Peasley, Wayne Pruchniak, Using Visual Basic 6, Que, 1998, p. 446. ISBN 9780789716330. W. Richard Stevens, Bill Fenner, Andrew M. Rudoff, UNIX Network Programming, Addison-Wesley, 2003, pp. 5–6, 29. ISBN 9780131411555. Kathi Fisler, CS 1101: Helper functions, Worcester Polytechnic Institute, 2005. Wenwen Wang, Helper function inlining in dynamic binary translation, CC: Compiler Construction, Association for Computing Machinery, 2021, p. 107. doi:10.1145/3446804.3446851. ISBN 978-1-4503-8325-7.

Voci correlate

Adapter pattern (Pattern adattatore) Decorator pattern (Pattern decoratore) Delegazione (programmazione) Forwarding (programmazione orientata agli oggetti) Language binding SWIG (generatore automatico di wrapper) Funzione annidata (Nested function) Applicazione parziale (Partial application)

Altri progetti

Collegamenti esterni

Categoria:Programmazione