Qual è la logica per rendere statici determinati metodi per i tipi di dati?

Aug 15 2020

In C#, ad esempio, esistono metodi statici per stabilire se una stringa è null o vuota , trovare un elemento in un array, cancellare un array, ecc. Tuttavia esiste un metodo di istanza per sostituire i caratteri in una stringa e sia statico che istanza metodi per copiare elementi tra array.

Allo stesso modo, in Python ci sono funzioni per ottenere la lunghezza di un elenco, per filtrare un elenco, ecc., ma metodi di istanza per trovare l'indice di un elemento e per copiare l'elenco.

Al contrario, in JavaScript, praticamente qualsiasi operazione che devo eseguire su un tipo di dati integrato sarà accessibile tramite il metodo o la proprietà dell'istanza.

Quindi qual è la logica per rendere certe cose statiche e altre no?

EDIT : Per essere chiari, capisco lo scopo dei metodi statici. La mia domanda è più sul motivo per cui alcuni metodi sono scritti come statici quando avrebbero potuto essere scritti come metodi di istanza. Come Findper gli array e Formatper le stringhe in C# filtere lenin Python.

Risposte

2 AvnerShahar-Kashtan Aug 15 2020 at 15:09

EDIT : la domanda è stata perfezionata, quindi perfezionerò la mia risposta, ma lascerò la precedente sotto per non rendere i commenti irrilevanti.

Ci possono essere diversi motivi per implementare un metodo come metodo statico invece di un metodo di istanza, con linguaggi o framework diversi che possono avere motivazioni diverse:

  1. L'interfaccia pubblica di un oggetto è un contratto. Se il tuo Arraytipo espone un Sortmetodo, ogni array d'ora in poi, indipendentemente dal tipo o dalla versione del linguaggio, deve supportarlo. Se, tuttavia, an Arrayè solo una rappresentazione di dati in memoria con un contratto sottile e la logica viene spostata in una classe come Array.Sort, ti offre maggiore flessibilità per estendere o modificare il tuo comportamento senza interrompere la compatibilità.

  2. Vedi questa citazione da Clean Code di Bob Martin :

Gli oggetti espongono il comportamento e nascondono i dati; La struttura dei dati espone i dati e non ha un comportamento significativo"

In questo caso, la Listclasse è una classe che espone il comportamento: nasconde i suoi dati (è implementata come un array ridimensionabile, ma questo è un dettaglio di implementazione), ma espone la funzionalità. An int[], tuttavia, è una struttura dati. intÈ un blocco allocato in sequenza . Ha una Lengthproprietà perché fa parte dei suoi dati , ma non ha molto comportamento: il comportamento viene scaricato su una classe che opera su di esso.

  1. Potrebbe essere una scelta stilistica. Python non è un linguaggio puramente OO e potrebbe non avere la garanzia Java/C# "tutto è un oggetto", quindi ha scelto di utilizzare funzioni del linguaggio come len()quelle che possono essere utilizzate indipendentemente dal fatto che il suo parametro sia o meno un'istanza di oggetto.

Risposta precedente

La logica alla base dei metodi statici in C# è avere metodi legati a un tipo ma non a un'istanza . Ci possono essere diverse ragioni per questo:

  1. I metodi che possono operare sia su un'istanza che su null, come string.IsNullOrEmpty, naturalmente non possono essere metodi di istanza, perché potrebbe non esserci un'istanza.
  2. Allo stesso modo, i metodi factory che creano un'istanza non hanno alcuna istanza da cui essere chiamati. Ad esempio, il metodo statico deprecato da qualcuno WebRequest.Create()restituisce una nuova istanza di un tipo derivato da WebRequest.
  3. Sebbene sia facile dimenticarlo, .NET ha una gestione diversa per un tipo integrale nativo ( int i =5) e un tipo di riferimento boxed attorno ad esso ( object boxed = 5). Se chiami un metodo su un tipo di valore ( int i = 5; t.ToString();), ti viene addebitato un costo per il boxing. Ecco perché alcune operazioni non sono definite come un metodo su un oggetto, ma come un metodo statico che accetta un valore. Ecco perché operazioni matematiche come Math.Absnon sono definite come metodi sui tipi boxed, ma come funzioni statiche che ricevono e restituiscono valori.
  4. A volte i metodi statici vengono utilizzati per "configurare" un tipo, non un'istanza specifica ma il comportamento di quel tipo nel sistema. Ad esempio, [ServicePointManager.SetTcpKeepAlive()][1]configura il comportamento di tutte le classi che utilizzano lo stack HTTP(s) condiviso in .NET, in modo da poterle configurare tutte tramite questi metodi statici.
5 amon Aug 15 2020 at 15:28

I metodi statici hanno molto senso

  • quando il metodo è correlato al tipo ma non richiede un'istanza esistente; o
  • quando la lingua supporta lo spazio dei nomi solo tramite le classi.

C# supporta solo funzioni come membri di classi, quindi le funzioni helper devono essere scritte come metodi statici. La classe C# Mathè un ottimo esempio.

JavaScript non ha classi, ma ogni variabile non locale è associata a qualche oggetto: nel browser, la maggior parte delle API è accessibile tramite l' windowoggetto. Tuttavia, ci sono metodi accessibili tramite un oggetto simile a una classe, ad esempio Array.isArray(x).

Python ha un design peculiare che è per lo più orientato agli oggetti, ma ha alcune funzioni integrate come len()o iter(), in gran parte per ragioni storiche. Sotto il cofano, invocano metodi reali, ad esempio iter(x)is di solito x.__iter__(), con un fallback per oggetti che possono essere indicizzati come un elenco.

Più interessanti sono i metodi che staticnon sono dovuti a stranezze della lingua, ma perché hanno senso. I metodi di tipo costruttore o di fabbrica sono il classico esempio in cui non abbiamo un oggetto esistente su cui poter chiamare un metodo. Alcune funzioni inoltre non operano esattamente su un oggetto, ad esempio String.IsNullOrEmpty(x)opera su zero o uno oggetti. Questo non funziona come metodo, ad esempio x.IsNullOrEmpty()genererebbe un'eccezione se è nullo! Il Array.isArray(x)metodo in JS è un altro ottimo esempio: vogliamo chiamare isArray(x)oggetti di qualsiasi tipo, non solo array. Pertanto, un metodo di istanza non funziona a meno che non faccia parte del prototipo di ogni oggetto.