DesempenhoDestaque SecundárioJavaJavascriptPHP

Como implementar uma classe singleton em Java e em outras linguagens

Você já se deparou com situações em que precisava que apenas uma instância de um objeto específico fosse compartilhada em todo o seu aplicativo? Imagine o cenário de uma Garrafa de Café de escritório, se cada funcionário que desejasse café, fosse fazer uma nova jarra de café. Em vez disso, todos compartilhariam a mesma garrafa, colocando café em suas xícaras conforme necessário. Este conceito de uma instância única e compartilhada está no objetivo principal das classes que utiliza o padrão singleton, e vamos ver como implementar isso em Java, e em seguida em outras linguagens como PHP, Python, JavaScript, C#, Go e Rust

O que é uma classe Singleton?

As classes singleton em Java garantem que apenas uma instância da classe seja criada e fornecem um ponto global de acesso a essa instância. Isto significa que qualquer parte do programa pode acessar a mesma instância da classe, permitindo o gerenciamento centralizado de recursos ou estado.

Singleton é um padrão de projeto de software. Este padrão garante a existência de apenas uma instância de uma classe, mantendo um ponto global de acesso ao seu objeto. Nota linguística: O termo vem do significado em inglês para um conjunto que contenha apenas um elemento. Wikipédia

Precisando de uma hospedagem de site ou de um servidor dedicado personalizado, seja para ambiente de teste, desenvolvimento ou de produção? E com um suporte de especialistas, que ti, ajudam a resolver os problemas o mais rápido possível? A SoloWeb tem o prazer em ti, ajudar com isso. Entre em contato conosco e faça uma cotação agora mesmo, acesse: www.soloweb.com.br.

Implementando uma classe Singleton: a analogia da Garrafa de Café

Vamos traduzir a analogia da garrafa de café em uma classe singleton Java chamada CoffeeBottle:

public class CoffeeBottle {
    private int coffeeQuantity = 900;
    private static CoffeeBottle instance = null;
    // Construtor privado para evitar instanciação externa
    private CoffeeBottle() {} 
    // Método para prestar o serviço de pegar/dar café
    public int getCoffee(int quantity){
        coffeeQuantity -= quantity;
        return quantity;
    }
    // Método para retornar o objeto ao usuário
    public static synchronized CoffeeBottle getInstance(){
        if(instance == null){
            instance = new CoffeeBottle();
        }
        return instance;
    }
    // Obter quantidade de café
    public int getCoffeeQuantity(){
        return coffeeQuantity;
    }
 }

Uma observação em relação à concorrência. Para proteger o código, a thread-safe, o que significa que se múltiplas threads chamarem o método getInstance() simultaneamente, e poder criar múltiplas instâncias da classe. E para tornar o Singleton thread-safe, adicionamos sincronização ao método getInstance(), ficando assim a assinatura: public static synchronized CoffeeBottle getInstance(){ … }

Compreendendo o Código:

  • Temos um construtor privado para evitar a instanciação externa da classe.
  • getInstance()método fornece uma maneira de acessar a única instância da classe. Se a instância ainda não estiver criada, ele cria uma e a retorna.
  • getCoffee()método simula o ato de tirar café da garrafa, reduzindo a quantidade de café.

Exemplo de uso:

// Testando e utilizando nossa classe
// Obtenha a instância singleton
CoffeeBottle cof = CoffeeBottle.getInstance();

// Funcionário usam a mesma garrafa para pegar café
int coffeeTaken = cof.getCoffee(50); // Funcionário gega 50ml
System.out.println("Café pego: " + coffeeTaken + "ml");
// Saída: Café pego: 50ml
System.out.println("Quantidade de café na garrafa: " + cof.getCoffeeQuantity() + "ml");
// Saída: Quantidade de café na garrafa: 850ml

// Outro funcionário pega 70 ml de café
coffeeTaken = cof.getCoffee(70); 
System.out.println("Café pego: " + coffeeTaken + "ml");
// Saída: Café pego: 70ml
System.out.println("Quantidade de café na garrafa: " + cof.getCoffeeQuantity() + "ml");
// Saída: Quantidade de café na garrafa: 780ml

Embora a implementação acima forneça uma forma básica de segurança, existem abordagens mais robustas.

As classes singleton em Java oferecem uma maneira conveniente de garantir que apenas uma instância de uma classe seja criada e acessada globalmente. Ao compreender o conceito por meio de analogias da vida real, como o cenário da garrafa de café do escritório, você pode compreender a importância e a utilidade das classes singleton em seus aplicativos.

E como fica em outras linguagens?

Agora vamos ver como fica esta classe na linguagem PHP

Em PHP, você pode implementar o padrão Singleton de maneira semelhante à forma como é feito em Java, embora com algumas diferenças sintáticas. Aqui está como o código poderia ser escrito em PHP:

class CoffeeBottle {
    private $coffeeQuantity = 900;
    private static $instance = null;
    // Construtor privado para evitar instanciação externa
    private function __construct() {} 
    // Método para prestar o serviço de pegar/dar café
    public function getCoffee($quantity){
        $this->coffeeQuantity -= $quantity;
        return $quantity;
    }
    // Método para retornar o objeto ao usuário
    public static function getInstance(){
        // Criará um novo objeto se o objeto ainda não tiver sido criado e retorna este
        if(self::$instance === null){
            self::$instance = new CoffeeBottle();
        }
        return self::$instance;
    }
    // Obter quantidade de café
    public function getCoffeeQuantity(){
        return $this->coffeeQuantity;
    }
}

// Testando e utilizando nossa classe
// Obtenha a instância singleton
$cof = CoffeeBottle::getInstance();

// Funcionário usam a mesma garrafa para pegar café
$coffeeTaken = $cof->getCoffee(50); // Funcionário pega 50ml
echo "Café pego: $coffeeTaken ml\n"; 
// Saída: Café pego: 50ml
echo "Quantidade de café na garrafa: " . $cof->getCoffeeQuantity() . " ml\n"; 
// Saída: Quantidade de café na garrafa: 850ml

Vamos ver como fica esta classe na linguagem Python

Em Python, implementar o padrão Singleton é um pouco diferente de outras linguagens, devido à natureza dinâmica e flexível da linguagem. Aqui está como você pode implementar o padrão Singleton em Python:

class CoffeeBottle:
    _instance = None
    def __init__(self):
        self._coffee_quantity = 900
    @staticmethod
    def get_instance():
        if CoffeeBottle._instance is None:
            CoffeeBottle._instance = CoffeeBottle()
        return CoffeeBottle._instance
    def get_coffee(self, quantity):
        self._coffee_quantity -= quantity
        return quantity
    def get_coffee_quantity(self):
        return self._coffee_quantity


# Testando e utilizando nossa classe
# Obtenha a instância singleton
cof = CoffeeBottle.get_instance()

# Funcionário usam a mesma garrafa para pegar café
coffee_taken = cof.get_coffee(50)  # Funcionário pega 50ml
print(f"Café pego: {coffee_taken} ml")  
# Saída: Café pego: 50ml
print(f"Quantidade de café na garrafa: {cof.get_coffee_quantity()} ml")  
# Saída: Quantidade de café na garrafa: 850ml

Agora vamos ver como fica essa implementação em JavaScript

Em JavaScript, o padrão Singleton pode ser implementado de várias maneiras devido à natureza flexível da linguagem. Aqui está uma maneira de implementá-lo usando uma função construtora:

let CoffeeBottle = (function () {
    let instance;
    function CoffeeBottle() {
        this.coffeeQuantity = 900;
    }
    CoffeeBottle.prototype.getCoffee = function (quantity) {
        this.coffeeQuantity -= quantity;
        return quantity;
    };
    CoffeeBottle.prototype.getCoffeeQuantity = function () {
        return this.coffeeQuantity;
    };
    return {
        getInstance: function () {
            if (!instance) {
                instance = new CoffeeBottle();
            }
            return instance;
        }
    };
})();

// Testando e utilizando nossa classe
// Obtenha a instância singleton
let cof = CoffeeBottle.getInstance();

// Funcionário usam a mesma garrafa para pegar café
let coffeeTaken = cof.getCoffee(50); // Funcionário pega 50ml
console.log("Café pego: " + coffeeTaken + " ml"); 
// Saída: Café pego: 50ml
console.log("Quantidade de café na garrafa: " + cof.getCoffeeQuantity() + " ml"); 
// Saída: Quantidade de café na garrafa: 850ml

Como fica em C#

Em C#, o padrão Singleton pode ser implementado de várias maneiras. Aqui está uma maneira comum de implementá-lo usando uma combinação de um campo privado estático e um método público estático para obter a instância única da classe:

public class CoffeeBottle
{
    private static CoffeeBottle instance;
    private int coffeeQuantity = 900;
    // Construtor privado para evitar instanciação externa
    private CoffeeBottle() { }
    // Método estático para retornar a instância única
    public static CoffeeBottle GetInstance()
    {
        // Cria uma nova instância se ainda não foi criada
        if (instance == null)
        {
            instance = new CoffeeBottle();
        }
        return instance;
    }
    // Método para prestar o serviço de pegar/dar café
    public int GetCoffee(int quantity)
    {
        coffeeQuantity -= quantity;
        return quantity;
    }
    // Método para retornar a quantidade de café na garrafa
    public int GetCoffeeQuantity()
    {
        return coffeeQuantity;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Testando e utilizando nossa classe
        // Obtenha a instância singleton
        CoffeeBottle cof = CoffeeBottle.GetInstance();

        // Funcionário usam a mesma garrafa para pegar café
        int coffeeTaken = cof.GetCoffee(50); // Funcionário pega 50ml
        Console.WriteLine("Café pego: " + coffeeTaken + "ml"); 
        // Saída: Café pego: 50ml
        Console.WriteLine("Quantidade de café na garrafa: " + cof.GetCoffeeQuantity() + "ml"); 
        // Saída: Quantidade de café na garrafa: 850ml
    }
}

Como fica na linguagem GO?

Em Go, o conceito de Singleton é um pouco diferente porque a linguagem não possui classes ou construtores no sentido tradicional. No entanto, podemos implementar um padrão similar garantindo que apenas uma instância de uma estrutura seja criada e acessada de forma segura. Uma forma comum de fazer isso é utilizando uma variável global e uma função para acessá-la. Aqui está um exemplo de como isso pode ser feito em Go:

package main

import (
    "fmt"
    "sync"
)
// CoffeeBottle representa a garrafa de café
type CoffeeBottle struct {
    coffeeQuantity int
}
// singletonInstance mantém a instância única da CoffeeBottle
var singletonInstance *CoffeeBottle
var once sync.Once
// GetInstance retorna a instância única de CoffeeBottle
func GetInstance() *CoffeeBottle {
    once.Do(func() {
        singletonInstance = &CoffeeBottle{coffeeQuantity: 900}
    })
    return singletonInstance
}
// GetCoffee pega uma quantidade específica de café da garrafa
func (c *CoffeeBottle) GetCoffee(quantity int) int {
    c.coffeeQuantity -= quantity
    return quantity
}
// GetCoffeeQuantity retorna a quantidade atual de café na garrafa
func (c *CoffeeBottle) GetCoffeeQuantity() int {
    return c.coffeeQuantity
}

func main() {
    // Testando e utilizando nossa classe
    // Obtenha a instância singleton
    cof := GetInstance()

    // Funcionário usam a mesma garrafa para pegar café
    coffeeTaken := cof.GetCoffee(50) // Funcionário pega 50ml
    fmt.Printf("Café pego: %d ml\n", coffeeTaken) 
    // Saída: Café pego: 50ml
    fmt.Printf("Quantidade de café na garrafa: %d ml\n", cof.GetCoffeeQuantity()) 
    // Saída: Quantidade de café na garrafa: 850ml
}

Neste exemplo em Go:

  • Criamos uma estrutura CoffeeBottle para representar a garrafa de café.
  • Usamos uma variável global singletonInstance para armazenar a única instância da estrutura CoffeeBottle.
  • Usamos a função GetInstance() para garantir que apenas uma instância de CoffeeBottle seja criada. Utilizamos o pacote sync e a função once.Do() para garantir que a inicialização seja executada apenas uma vez.
  • Implementamos métodos na estrutura CoffeeBottle para pegar café e verificar a quantidade de café na garrafa.
  • No método main(), testamos e usamos a classe CoffeeBottle para demonstrar o padrão Singleton em ação.

E a implementação desta classe em Rust?

Em Rust, o conceito de Singleton é um pouco diferente de outras linguagens de programação, devido às restrições de propriedade e ao sistema de tipos de Rust. Uma maneira comum de implementar um padrão similar é usando um módulo para encapsular a instância única e fornecer uma função para acessá-la. Aqui está um exemplo de como isso pode ser feito em Rust:

use std::sync::{Arc, Mutex};

// Struct que representa a garrafa de café
pub struct CoffeeBottle {
    coffee_quantity: i32,
}

// Função para criar a instância única de CoffeeBottle
pub fn get_instance() -> Arc<Mutex<CoffeeBottle>> {
    static mut INSTANCE: Option<Arc<Mutex<CoffeeBottle>>> = None;
    static INIT: std::sync::Once = std::sync::Once::new();
    INIT.call_once(|| {
        unsafe {
            INSTANCE = Some(Arc::new(Mutex::new(CoffeeBottle { coffee_quantity: 900 })));
        }
    });
    unsafe { INSTANCE.clone().unwrap() }
}

impl CoffeeBottle {
    // Método para pegar uma quantidade específica de café da garrafa
    pub fn get_coffee(&mut self, quantity: i32) -> i32 {
        self.coffee_quantity -= quantity;
        quantity
    }
    // Método para obter a quantidade atual de café na garrafa
    pub fn get_coffee_quantity(&self) -> i32 {
        self.coffee_quantity
    }
}

fn main() {
    // Testando e utilizando nossa classe
    // Obtenha a instância singleton
    let mut cof = get_instance().lock().unwrap();

    // Funcionário usam a mesma garrafa para pegar café
    let coffee_taken = cof.get_coffee(50); // Funcionário pega 50ml
    println!("Café pego: {} ml", coffee_taken); 
    // Saída: Café pego: 50ml
    println!("Quantidade de café na garrafa: {} ml", cof.get_coffee_quantity()); 
    // Saída: Quantidade de café na garrafa: 850ml
}
Esperamos ter ajudado com mais esta dica, e siga nos, nas redes sociais para mais tutoriais, e se precisar de nossa ajuda estamos a disposição: www.soloweb.com.br.

E lembrando que a SOLOWEB além de oferecer Hospedagem de Sites, Servidores Dedicados, Servidores VPS com o menor custo do Brasil, também desenvolve soluções de software e realiza gerenciamento e monitoramento de servidores para sua empresa, faça uma cotação sem custo, acesse: www.soloweb.com.br