Singleton

Mattepuffo's logo
Singleton

Singleton

Il Singleton è un Design pattern molto usato nell'ambito della programmazione a oggetti.

Detta in maniera breve e brutale, una classe Singleton è una classe che garantisce che soltanto un'unica istanza della classe stessa possa essere creata all'interno di un programma.

Costruire una classe Singleton non è difficile, basta seguire alcune specifiche:

  • il costruttore deve essre private
  • ci si avvale di un metodo statico per accedere all'unica istanza della classe
  • gli altri metodi non sono statici

Vediamo qualche esempio generico in Java e C#.

Java:

public class Singleton {

private static class Singleton instance;

private Singleton() { } // costruttore privato

public static Singleton getInstance() {

return (instance == null) ? (instance = new Singleton()) : instance;

}

// altri metodi non statici

}

C# (esempio ripreso da HTML.it):

using System; public class Singleton { private static Singleton istanza; private Singleton() {} public static Singleton Instance { get { if (instanza == null) { istanza = new Singleton(); } return istanza; } } public void helloWorld() { Console.WriteLine("Hello World"); } } public class usaSingleton { public static void Main() { Singleton.Instance.helloWorld(); } }

Singleton potrebbe usato in tutti quei casi in cui si accede spesso ad una classe di supporto.

 

 

I vantaggi sono:

  • avere un accesso controllato all'unica istanza della classe
  • avere uno spazio di nomi ridotto
  • evitare la dichiarazione di variabili globali
  • assicurarsi di avere un basso numero di oggetti utilizzati in condivisione grazie al fatto che viene impedita la creazione di nuove istanze ogni volta che si voglia utilizzare la stessa classe

Io l'ho usato per la classe con la quale svolgo le operazioni su db MySQL.

Vi posto il mio esempio (in Java):

import java.sql.*;
import java.util.ArrayList;
import javax.swing.table.DefaultTableModel;

public class DBManager {

private static DBManager instance = null;
final static String HOST = "";
final static String DB = "";
final static String USER = "";
final static String PWD = "";
private static Connection conn = null;

private DBManager() {
}

public static DBManager getInstance() {
return (instance == null) ? (instance = new DBManager()) : instance;
}

public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://" + HOST + ":3306/" + DB + "?user=" + USER + "&password=" + PWD);
return conn;
}

public void select() throws ClassNotFoundException, SQLException {
conn = DBManager.getInstance().getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM bookv");
while (rs.next()) {
String id = rs.getString("book_id");
String name = rs.getString("name");
String author = rs.getString("author_name");
String editor = rs.getString("editor_name");
String price = rs.getString("price");
String isbn = rs.getString("isbn");
String note = rs.getString("note");
Object[] riga = {id, name, author, editor, price, isbn, note};
((DefaultTableModel) Main.getTable().getModel()).addRow(riga);
}
rs.close();
stmt.close();
}

public void insert(String name, int author_id, int editor_id, double price, String isbn, String note) throws ClassNotFoundException, SQLException {
String sql = "INSERT book (name, author_id, editor_id, price, isbn, note) VALUES ('" + name + "', " + author_id + ", " + editor_id + ", " + price + ", '" + isbn + "', '" + note + "')";
conn = DBManager.getInstance().getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql);
}

public void update(int id, String name, int author_id, int editor_id, double price, String isbn, String note) throws ClassNotFoundException, SQLException {
String sql = "UPDATE book SET name = '" + name + "', author_id = " + author_id + ", editor_id = " + editor_id + ", price = " + price + ", isbn = '" + isbn + "', note = '" + note + "' WHERE book_id = " + id;
conn = DBManager.getInstance().getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql);
stmt.close();
}

public void elimina(int id) throws ClassNotFoundException, SQLException {
conn = DBManager.getInstance().getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate("DELETE FROM movimenti WHERE book_id='" + id + "'");
stmt.close();
}

.......

}

Ci sono poi tutti gli altri metodi.

Come vedet nesusn metodo è statico tranne getInstance che altro non fa che istanziare la classe.

Per richiamare questa classe si procede così (esempio ripreso dal mio JFrame dal quale eseguo le varie operazioni):

import java.sql.SQLException;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class Main extends javax.swing.JFrame {

private DBManager dbman = DBManager.getInstance();

public Main() {
initComponents();
}

......

// evento in cui richiamo il metodo select

private void labelTableMouseClicked(java.awt.event.MouseEvent evt) {                                        
try {
DefaultTableModel newModel = (DefaultTableModel) tableData.getModel();
while (newModel.getRowCount() > 0) {
newModel.removeRow(0);
}
dbman.select();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
} catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
}

......

In pratica si crea un unico oggetto della classe Singleton, e su di esso si richiamano i vari metodi quando servono.

In questo cso ho richiamato select per rimpire la JTable.

Ovviamente questo pattern può essere per tutto i linguaggi.

 

Ed ecco il pattern in PHP.

Vi riporto una parte della classe:

<?php

class Config {

private $pdo;
private static $instance;

private function __construct() {
try {
$this->pdo = new PDO('mysql:host=host;dbname=db', "user", "pass", array(
PDO::ATTR_PERSISTENT => TRUE
));
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}

public static function getInstance() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}

public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}

public function select() {
$result = array();
try {
$result = $this->pdo->query("CALL getBook()");
return $result;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}

.........

Il costruttore è privato e dentro viene istanziata la connessio con PDO.

Il metodo getInstance() si comporta esattamente come il metodo omonimo negli altri esempi.

Se la variabile privata $instance è NULL viene creata una sua istanza.

__CLASS__ rappresenta il nome della classe.

Nella funzione __clone() evitiamo che la classe venga clonata.

select() è un metodo per eseguire la query.

Adesso per richiamare questo metodo dentro un altro file:

<?php
include_once 'config.php';
$sel_mod = Config::getInstance();
return $sel_mod->select();


Grazie ad Alex'87 del forum HTML.it


Condividi

Commentami!