Devo fornire funzioni parziali basate sulla chiamata API in Clojure?

3

Sto progettando una libreria per racchiudere un'API con Clojure. L'API richiede le credenziali dell'utente per autenticare le chiamate relative all'utente.

Il mio primo approccio era quello di avere funzioni che eseguono ogni compito che l'API può fare:

(defn send-email
  [credentials email]
  (call-api credentials :email email))

(defn send-message
  [credentials message]
  (call-api credentials :say message))

Tuttavia, ho notato che la maggior parte delle funzioni ha lo stesso argomento, credentials . Quindi, ho pensato ad un altro modo di affrontare questo. Come restituire le funzioni partial ed con le credenziali dopo l'accesso:

(defn authenticate
    [username password]
    (let [credentials (api-auth username password)]
      {:credentials credentials
        :send-email (partial send-email credentials)
        :send-message (partial send-message credentials)})

Ciò lo rende molto più conveniente, l'utente di questa libreria non ha bisogno di aggiungere le credenziali per ogni chiamata.

Ma aspetta, sembra molto simile a quello che faresti nella programmazione orientata agli oggetti. Passi qualcosa in una funzione (l'inizializzatore) e ottieni funzioni (da un oggetto) su misura per ciò che hai passato.

Quanto sopra potrebbe essere stato scritto come questo in Java:

public class Api {
    private String credentials;
    Api(String username, String password) {
        this.credentials = Utils.api_auth(username, password);
    }

    void send_email(String email) {
        Utils.call_api(this.credentials, Utils.EMAIL, email);
    }

    void send_message(String message) {
        Utils.call_api(this.credentials, Utils.SAY, message);
    }
}

Poiché Clojure è un linguaggio di programmazione funzionale , voglio evitare la programmazione orientata agli oggetti, ma mi sembra che l'intero compito fosse destinato ai linguaggi di programmazione orientati agli oggetti.

Come dovrei progettare una tale API? Quale approccio dovrei scegliere, o c'è qualcosa a cui non sto pensando nella mia mente orientata agli oggetti?

Aggiorna Ho pensato ad un terzo modo: binding s:

(def ^:dynamic *credentials*)

(defn send-email
  [email]
  (call-api *credentials* :email email))

(defn send-message
  [message]
  (call-api *credentials* :say message))
; Usage
(binding [*credentials* (api-auth username password)]
  (send-email "hello")
  (send-message "hello"))

Tuttavia, il problema con questo è che è molto facile creare codice errato, semplicemente non legare nulla all'inizio. Questo è diverso dalle implementazioni di vars dinamici che ho visto ( pprint ), dove c'è un bind predefinito.

    
posta Moon Cheesez 05.08.2017 - 07:14
fonte

2 risposte

0

Non sei sicuro che sia abbastanza "funzionale" per te, ma potresti sostituire call-api con call-auth-api e in tal modo ottenere credenziali, possibilmente da un archivio a durata limitata, e fornirle come uno degli input per % effettivo% di sconto.

    
risposta data 05.08.2017 - 10:44
fonte
0

OO requires objects have mutable attributes

No, OO richiede che gli oggetti abbiano attributi. C'è un sacco di codice OO che usa oggetti con attributi mutabili e anche un sacco di codice OO che usa oggetti con solo attributi immutabili .

Dai un'occhiata alla classe String di Java, tutte le operazioni ti danno nuovo String s, invece di mutare il contenuto di this .

    
risposta data 04.01.2019 - 13:43
fonte

Leggi altre domande sui tag