2009-02-10 14 views
6

Inserendo funzionalità in una funzione, solo questo costituisce un esempio di incapsulamento o è necessario utilizzare oggetti per l'incapsulamento?Una funzione è un esempio di incapsulamento?

Sto cercando di capire il concetto di incapsulamento. Quello che ho pensato è stata se vado da qualcosa di simile:

n = n + 1

che viene eseguito fuori in natura come parte di un grande corpo di codice e poi lo prendo, e metterlo in una funzione come questa, allora ho incapsulato che la logica, oltre a un metodo:

addOne(n) 
    n = n + 1 
    return n 

o è più il caso che è solo l'incapsulamento se mi sto nascondendo i dettagli della addOne dal mondo esterno - come se si tratta di un metodo a oggetti e utilizzo un modificatore di accesso privato/protetto?

risposta

12

Forse si sta confondendo astrazione con incapsulamento, intesa nel più ampio contesto di orientamento agli oggetti.

incapsulamento comprende correttamente tutti e tre i seguenti:

  • Astrazione
  • Attuazione Nascondere
  • divisione di responsabilità

astrazione è solo una componente di incapsulamento. Nel tuo esempio hai astratto la funzionalità di aggiunta dal corpo principale del codice in cui un tempo risiedeva. Lo fai identificando alcuni elementi comuni nel codice, riconoscendo un concetto (aggiunta) su un caso specifico (aggiungendo il numero uno alla variabile n). Grazie a questa capacità, l'astrazione rende riutilizzabile un componente incapsulato, un metodo o un oggetto.

Altrettanto importante per la nozione di incapsulamento è l'idea di occultamento dell'implementazione. Questo è il motivo per cui l'incapsulamento è discusso nell'arena dell'orientamento agli oggetti. L'occultamento dell'implementazione protegge un oggetto dai suoi utenti e viceversa. In OO, lo fai presentando un'interfaccia di metodi pubblici agli utenti del tuo oggetto, mentre l'implementazione dell'oggetto avviene all'interno di metodi privati.

Questo ha due vantaggi. Innanzitutto, limitando l'accesso all'oggetto, si evita una situazione in cui gli utenti dell'oggetto possono lasciare l'oggetto in uno stato non valido. In secondo luogo, dal punto di vista dell'utente, quando usano il tuo oggetto si accoppiano solo in modo approssimativo - se cambi la tua implementazione in un secondo momento, non ne risentiranno.

Infine, la divisione della responsabilità - nel più ampio contesto di un progetto OO - è qualcosa che deve essere considerato per affrontare correttamente l'incapsulamento. È inutile racchiudere una raccolta casuale di funzioni - la responsabilità deve essere definita in modo pulito e logico in modo tale che ci sia una sovrapposizione o ambiguità il più possibile ridotta. Ad esempio, se disponiamo di un oggetto da toilette, vorremmo rimuovere il suo dominio di responsabilità dal nostro oggetto Kitchen.

In senso limitato, tuttavia, si è certi che una funzione, diciamo, "modularizza" alcune funzionalità estraendola. Ma, come ho detto, "incapsulamento" come termine è inteso nel più ampio contesto dell'orientamento agli oggetti da applicare a una forma di modularizzazione che soddisfi i tre criteri sopra elencati.

+0

Se la funzione è stata chiamata "AddX" dove X è un valore che al momento ha un valore di 1 ma questo potrebbe cambiare, allora ci sarebbe l'informazione che si nasconde. Il valore specifico da aggiungere sarebbe nascosto nella definizione della funzione. –

+0

Inoltre, le funzioni sicuramente dividono la responsabilità. Ogni funzione si assume la responsabilità di qualcosa che le altre funzioni non fanno. Sì, un determinato insieme di funzioni può essere progettato male in modo che si sovrappongano, ma lo stesso vale per un insieme di classi mal progettato. –

+0

@Serx La funzione addOne esprime "cosa" fa e nasconde "come" lo fa. Quindi questo si qualifica come l'astrazione + l'occultamento delle informazioni. Perché sei così concentrato sugli oggetti? E come afferma Earwicker, le funzioni possono dividere la responsabilità, ma trovo questo un criterio piuttosto vago per l'incapsulamento. – eljenso

1

E 'una cosa a livello di componente

check this out:

In informatica, incapsulamento è il nascondiglio dei meccanismi interni e le strutture di dati di un componente software dietro un interfaccia definita, in tale un modo in cui gli utenti del componente (altri pezzi di software) devono solo sapere cosa fa il componente e non possono rendersi dipendenti dai dettagli di come lo fa. Lo scopo è raggiungere il potenziale di cambiamento: i meccanismi interni del componente possono essere migliorati senza impatto su altri componenti, oppure il componente può essere sostituito con uno diverso che supporta la stessa interfaccia pubblica.

(non ho ben capito la tua domanda, fatemi sapere se quel collegamento non copre i vostri dubbi)

-1

Non è normalmente molto senso parlare di incapsulamento senza riferimento a proprietà, piuttosto che esclusivamente Metodi - è possibile inserire i controlli di accesso sui metodi, certamente, ma è difficile vedere come ciò sarà diverso da assurdo senza alcun ambito di dati per il metodo incapsulato. Probabilmente potresti fare qualche argomento per convalidarlo, ma sospetto che sarebbe tortuoso.

Quindi no, molto probabilmente non si utilizza l'incapsulamento solo perché si mette un metodo in una classe piuttosto che averlo come funzione globale.

+0

caos perché è giù voto? cosa c'è di sbagliato qui? –

+0

@Foysal: non ne ho idea. – chaos

1

Il concetto astratto di incapsulamento significa che si nascondono i dettagli di implementazione. L'orientamento all'oggetto non è che un esempio dell'uso dell'ecnapsulazione. Un altro esempio è il linguaggio chiamato module-2 che utilizza (o usa) moduli di implementazione e moduli di definizione. I moduli di definizione nascondevano l'effettiva implementazione e quindi fornivano l'incapsulamento.

L'incapsulamento viene utilizzato quando si può considerare qualcosa una scatola nera. Gli oggetti sono una scatola nera. Conoscete i metodi che forniscono, ma non come sono implementati.

[EDIT] Come per l'esempio nella domanda aggiornata: dipende da quanto ristretta o ampia si definisce l'incapsulamento. Il tuo esempio AddOne non nasconde nulla in cui credo. Sarebbe un nascondiglio/incapsulamento delle informazioni se la tua variabile fosse un indice di array e chiameresti il ​​tuo metodo moveNext e magari avresti un'altra funzione setValue e getValue. Ciò consentirebbe alle persone (insieme forse con alcune altre funzioni) di navigare nella struttura e nell'impostazione e di ottenere variabili con loro essendo consapevoli che si sta utilizzando un array.Se il linguaggio di programmazione supportava concetti diversi o più ricchi, è possibile modificare l'implementazione di moveNext, setValue e getValue cambiando il significato e l'interfaccia. Per me questo è l'incapsulamento.

+0

Ho aggiornato la mia domanda per chiarire l'ambiguità (si spera). –

15

Sarò il primo a non essere d'accordo con quella che sembra essere la tendenza della risposta. Sì, una funzione racchiude una parte dell'implementazione. Non hai bisogno di un oggetto (che penso tu usi per indicare una classe).

Vedere anche Meyers.

+0

Avrei pensato che la risposta fosse ovviamente sì.Quando si chiama una funzione, non bisogna preoccuparsi di come la funzione sta svolgendo il lavoro. –

+0

concordato. Sembra ovvio anche a me. Alcune persone rimangono semplicemente bloccate su ciò che il loro libro di testo OOP ha detto. Tornando alla definizione, quell'incapsulamento nasconde i dettagli di implementazione in modo che l'utente non debba preoccuparsi di essi, una funzione è ovviamente un esempio di incapsulamento. – jalf

+0

Giusto. Il fatto è, puoi cambiare l'implementazione senza influenzare il codice usando l'implementazione? Se è così, quel comportamento (ciò che fa quel codice) è incapsulato. – alphadogg

3

Un metodo non è più un esempio di incapsulamento di un'automobile è un esempio di buona guida. L'incapsulamento non riguarda la sinossi, è un problema di progettazione logica. Sia gli oggetti che i metodi possono presentare l'incapsulamento buono e cattivo.

Il modo più semplice di pensarci è se il codice nasconde/astrae i dettagli da altre parti del codice che non hanno bisogno di sapere/preoccuparsi dell'implementazione.

Tornando alla macchina esempio: La trasmissione automatica offre una buona incapsulamento: come guidatore ti interessa avanti/indietro e velocità. La trasmissione manuale è incapsulamento errato: dal punto di vista del guidatore, l'ingranaggio specifico richiesto per le basse/alte velocità è generalmente irrilevante per l'intento del conducente.

+0

Capito. L'esempio di trasmissione è molto chiaro. Grazie. –

3

No, gli oggetti non sono richiesti per l'incapsulamento. Nel senso più ampio, "incapsulamento" significa semplicemente "nascondere i dettagli dalla vista" e, a tale proposito, un metodo sta incapsulando i suoi dettagli di implementazione.

Ciò non significa in realtà che tu possa uscire e dire che il tuo codice è ben progettato solo perché lo hai diviso in metodi, però. Un programma composto da 500 metodi pubblici non è molto meglio di quello stesso programma implementato in un metodo a 1000 righe.

Nella creazione di un programma, indipendentemente dal fatto che si utilizzino o meno tecniche orientate agli oggetti, è necessario pensare all'incapsulamento in molti punti diversi: nascondere i dettagli di implementazione di un metodo, nascondere i dati dal codice che non necessita a sapere, la semplificazione delle interfacce ai moduli, ecc

Aggiornamento: per rispondere alla tua domanda aggiornato, sia "mettere il codice in un metodo" e "con un modificatore di accesso" sono diversi modi di incapsulare la logica, ma ogni uno agisce a un livello diverso.

Inserire il codice in un metodo nasconde le singole righe di codice che compongono tale metodo in modo che i chiamanti non debbano preoccuparsi di quali siano quelle linee; si preoccupano solo della firma del metodo.

Contrassegnare un metodo su una classe come (per esempio) "privato" nasconde tale metodo in modo che un utente della classe non debba preoccuparsi di ciò; si preoccupano solo dei metodi pubblici (o delle proprietà) della tua classe.

+0

Non puoi nemmeno dire che il tuo codice è ben progettato solo perché lo hai diviso in classi, oppure;) –

+0

@Mo oh, certamente. Il mio punto era che se scegliessi l'incapsulamento lungo un singolo asse o un singolo livello di astrazione e poi dicevi "bene, indovina il mio programma incapsulato", stai sbagliando. –

5

Sicuro che lo sia.

Ad esempio, un metodo che opera solo sui suoi parametri sarebbe considerato "meglio incapsulato" di un metodo che opera su dati statici globali.

incapsulamento è stato intorno a lungo prima OOP :)

1

Semplifichiamo un po 'questo con un'analogia: si gira la chiave della macchina e si avvia. Sai che non c'è solo la chiave, ma non lo hai per sapere che quello che sta succedendo. Per te, svolta chiave = avvio motore. L'interfaccia della chiave (vale a dire, la chiamata di funzione) nasconde l'implementazione del motorino di avviamento che gira il motore, ecc ... (l'implementazione). Questo è l'incapsulamento. Sei risparmiato dal dover sapere cosa sta succedendo sotto il cofano, e sei felice per questo.

Se è stata creata una mano artificiale, ad esempio per girare la chiave, è l'incapsulamento non. Stai girando la chiave con ulteriori middleman cruft senza nascondere nulla. Questo è ciò che il tuo esempio mi ricorda - non incapsula i dettagli di implementazione, anche se entrambi sono realizzati attraverso chiamate di funzione. In questo esempio, chiunque raccogli il tuo codice non ti ringrazierà per questo. In effetti, saranno più propensi a prenderti a calci con la tua mano artificiale.

Per l'incapsulamento è possibile utilizzare qualsiasi metodo a cui è possibile nascondere informazioni (classi, funzioni, librerie dinamiche, macro).

+0

Mi piace il tuo esempio di motore ma mi hai perso con il tuo divertente esempio di mano artificiale. –

0

il modello di riferimento Open Distributed Processing - scritta dalla International Organization for Standardization - definisce i seguenti concetti:

entità: Qualsiasi calcestruzzo o cosa astratta di interesse.

Oggetto: un modello di un'entità. Un oggetto è caratterizzato dal suo comportamento e, dualmente, dal suo stato.

Comportamento (di un oggetto): una raccolta di azioni con un insieme di vincoli su quando possono verificarsi.

Interfaccia: Un'astrazione del comportamento di un oggetto costituito da un sottoinsieme delle interazioni di quell'oggetto insieme a un insieme di vincoli su quando possono verificarsi.

Incapsulamento: la proprietà che le informazioni contenute in un oggetto sono accessibili solo attraverso le interazioni sulle interfacce supportate dall'oggetto.

Questi, lo apprezzerete, sono abbastanza ampi. Vediamo, tuttavia, se la funzionalità di una funzione all'interno di una funzione può essere considerata logicamente da costituire all'incapsulamento in questi termini.

In primo luogo, una funzione è chiaramente un modello di "Cosa di interesse", in quanto rappresenta un algoritmo che tu (presumibilmente) desideri eseguito e che l'algoritmo riguarda un problema che stai cercando di risolvere (e quindi è un modello di esso).

Una funzione ha un comportamento? Certamente: contiene una raccolta di azioni (che potrebbero essere un numero qualsiasi di istruzioni eseguibili) che vengono eseguite con il vincolo che la funzione deve essere chiamata da qualche parte prima che possa essere eseguita. Una funzione non può essere chiamata spontaneamente in qualsiasi momento, senza un fattore causale. Sembra legalese? Scommetti. Ma andiamo avanti, comunque.

Una funzione ha un'interfaccia? Certamente: ha un nome e una collezione di parametri formali, che a loro volta si associano alle istruzioni eseguibili contenute nella funzione in quanto, una volta chiamata una funzione, il nome e l'elenco dei parametri sono intesi per identificare in modo univoco la raccolta di eseguibili le dichiarazioni devono essere eseguite senza che la parte chiamante specifichi tali dichiarazioni effettive.

Una funzione ha la proprietà che le informazioni contenute nella funzione sono accessibili solo attraverso le interazioni sulle interfacce supportate dall'oggetto? Hmm, bene, può.

Poiché alcune informazioni sono accessibili tramite la relativa interfaccia, alcune informazioni devono essere nascoste e inaccessibili all'interno della funzione. (La proprietà che tali informazioni esibiscono è chiamata "nascondere le informazioni", definita da Parnas sostenendo che i moduli dovrebbero essere progettati per nascondere sia le decisioni difficili che le decisioni che potrebbero cambiare.) Quindi quali informazioni sono nascoste all'interno di una funzione?

Per vedere questo, dovremmo prima considerare la scala. È facile affermare che, ad esempio, le classi Java possono essere incapsulate all'interno di un pacchetto: alcune delle classi saranno pubbliche (e quindi saranno l'interfaccia del pacchetto) e alcune saranno private del pacchetto (e quindi nascoste nel pacchetto). . Nella teoria di incapsulamento, le classi formano nodi e le confezioni formano regioni incapsulate, con la totalità che forma un grafo incapsulato; il grafico di classi e pacchetti è chiamato il terzo grafico.

È anche facile affermare che le funzioni (oi metodi) stessi sono incapsulate all'interno delle classi. Ancora una volta, alcune funzioni saranno pubbliche (e quindi faranno parte dell'interfaccia della classe) e alcune saranno private (e quindi informazioni nascoste all'interno della classe).Il grafico delle funzioni e delle classi è chiamato il secondo grafico.

Ora arriviamo alle funzioni. Se le funzioni devono essere un mezzo di incapsulamento, devono contenere alcune informazioni pubbliche ad altre funzioni e alcune informazioni che sono nascoste all'interno della funzione. Quale potrebbe essere questa informazione?

Un candidato ci viene assegnato da McCabe. Nel suo famoso documento sulla complessità ciclomatica, Thomas McCabe descrive il codice sorgente in cui, "Ogni nodo nel grafico corrisponde a un blocco di codice nel programma in cui il flusso è sequenziale e gli archi corrispondono a rami presi nel programma."

Prendiamo il blocco di esecuzione sequenziale di McCabian come unità di informazioni che può essere incapsulata all'interno di una funzione. Poiché il primo blocco all'interno della funzione è sempre il primo e unico blocco garantito da eseguire, possiamo considerare il primo blocco come pubblico, in quanto può essere chiamato da altre funzioni. Tutti gli altri blocchi all'interno della funzione, tuttavia, non possono essere richiamati da altre funzioni (eccetto che nelle lingue che consentono di saltare nelle funzioni a metà del flusso) e quindi questi blocchi possono essere considerati informazioni nascoste all'interno della funzione.

Prendendo queste definizioni (forse un po 'tenue), allora potremmo dire di sì: mettere funzionalità in una funzione costituisce un incapsulamento. L'incapsulamento dei blocchi all'interno delle funzioni è il primo grafico.

C'è un caveate, tuttavia. Prenderesti in considerazione un pacchetto di cui ogni classe era pubblica per essere incapsulata? Secondo le definizioni di cui sopra, supera il test, come si può dire che l'interfaccia al pacchetto (cioè tutte le classi pubbliche) offre effettivamente un sottoinsieme del comportamento del pacchetto ad altri pacchetti. Ma il sottoinsieme in questo caso è l'intero comportamento del pacchetto, in quanto nessuna classe è nascosta. Quindi, nonostante soddisfino in modo soddisfacente le definizioni di cui sopra, riteniamo che non soddisfi lo spirito delle definizioni, poiché sicuramente qualcosa deve essere nascosto dalle informazioni per poter essere rivendicato il vero incapsulamento.

Lo stesso vale per l'esempio che dai. Possiamo certamente considerare n = n + 1 come un singolo blocco di McCabian, dato che (e la dichiarazione di ritorno) sono un flusso sequenziale di esecuzioni. Ma la funzione in cui si inserisce questo contiene solo un blocco, e quel blocco è l'unico blocco pubblico della funzione, e quindi non ci sono blocchi nascosti di informazioni all'interno della funzione proposta. Quindi può soddisfare la definizione di incapsulamento, ma direi che non soddisfa lo spirito.

Tutto questo, ovviamente, è accademico a meno che non si possa dimostrare un vantaggio tale incapsulamento.

Ci sono due forze che motivano l'incapsulamento: il semantico e il logico.

L'incapsulamento semantico indica semplicemente l'incapsulamento basato sul significato dei nodi (per usare il termine generale) incapsulato. Quindi se ti dico che ho due pacchetti, uno chiamato 'animale' e uno chiamato 'minerale', quindi ti do tre classi Cane, Gatto e Capra e chiedi in quali pacchetti queste classi dovrebbero essere incapsulate, quindi, dato senza altre informazioni, avresti perfettamente ragione nel sostenere che la semantica del sistema suggerirebbe che le tre classi fossero incapsulate all'interno del pacchetto "animale" piuttosto che "minerale".

L'altra motivazione per l'incapsulamento, tuttavia, è logica.

La configurazione di un sistema è l'identificazione precisa ed esaustiva di ciascun nodo del sistema e della regione incapsulata in cui risiede; una particolare configurazione di un sistema Java è - al terzo grafico - per identificare tutte le classi del sistema e specificare il pacchetto in cui ogni classe risiede.

Per incapsulare un sistema logicamente significa identificare alcune proprietà matematiche del sistema che dipendono dalla sua configurazione e quindi configurare tale sistema in modo tale che la proprietà venga minimizzata matematicamente.

La teoria di incapsulamento propone che tutti i grafici incapsulati esprimano un numero massimo potenziale di bordi (MPE). In un sistema Java di classi e pacchetti, ad esempio, l'MPE è il numero massimo potenziale di dipendenze del codice sorgente che possono esistere tra tutte le classi di quel sistema. Due classi all'interno dello stesso pacchetto non possono essere nascoste dall'informazione e quindi entrambe possono potenzialmente formare delle responsabilità l'una sull'altra. Due classi private di pacchetti in pacchetti separati, tuttavia, non possono formare dipendenze l'una dall'altra.

La teoria dell'incapsulazione ci dice quanti pacchetti dovremmo avere per un dato numero di classi in modo che l'errore massimo tollerato sia ridotto al minimo. Questo può essere utile perché la debole forma del Principio di Burden afferma che il massimo carico potenziale di trasformare una raccolta di entità è una funzione del numero massimo potenziale di entità trasformate - in altre parole, maggiore è la potenziale dipendenza del codice sorgente tra le tue lezioni, maggiore è il costo potenziale di fare un particolare aggiornamento. Ridurre al minimo l'errore massimo consentito riduce quindi al minimo il costo potenziale degli aggiornamenti.

Dato n classi e un requisito di p classi pubbliche per pacchetto, la teoria di incapsulamento mostra che il numero di pacchetti, r, dovremmo ridurre l'MPE è dato dall'equazione: r = sqrt (n/p).

Questo vale anche per il numero di funzioni che dovreste avere, dato il numero totale, n, di blocchi di McCabian nel vostro sistema. Le funzioni hanno sempre un solo blocco pubblico, come menzionato sopra, e quindi l'equazione per il numero di funzioni, r, da avere nel tuo sistema semplifica: r = sqrt (n).

Certamente, pochi hanno considerato il numero totale di blocchi nel loro sistema quando praticano l'incapsulamento, ma è prontamente fatto a livello di classe/pacchetto. Inoltre, minimizzare l'MPE è quasi del tutto intuitivo: è fatto riducendo al minimo il numero di classi pubbliche e cercando di distribuire uniformemente le classi sui pacchetti (o almeno evitare di avere molti pacchetti con, diciamo, 30 classi e un pacakge di mostri con 500 classi, nel qual caso l'MPE interno di quest'ultimo può facilmente sopraffare l'MPE di tutti gli altri).

L'incapsulamento comporta quindi un equilibrio tra il semantico e il logico.

Tutto molto divertente.

0

nella rigorosa terminologia orientata agli oggetti, si potrebbe essere tentati di dire no, una "semplice" funzione non è sufficientemente potente per essere chiamata incapsulamento ... ma in the real world la risposta ovvia è "sì, una funzione incapsula del codice" .

per i puristi OO che si lamentano di questa bestemmia, si consideri una classe anonima statica senza stato e un unico metodo; se la funzione AddOne() non è incapsulamento, allora neanche questa classe!

e solo per essere pedante, l'incapsulamento è una forma di astrazione, non viceversa. ;-)

1

L'incapsulamento è un processo in cui attributi (membro dati) e comportamento (funzione membro) di un oggetto in combinazione insieme come entità singola si riferiscono come classe.

Problemi correlati