Skip to content
Home » Blog » Singleton design pattern

Singleton design pattern

The time has come for the first design pattern I have described, namely Singleton. It is a creative design pattern whose assumptions are very simple. Nevertheless, using this pattern we get a very convenient tool. Why? I encourage you to read the article.

Let's build a Pattern from scratch

Let's start by presenting the very idea and the purpose of using this pattern. This pattern is to control that only one object of a given class is created during the operation of the application. The programmer does not have to focus on creating mechanisms referring to the same object by himself, because the class itself makes sure that no more objects are created.

By default, when creating an object, we use the constructor of a given class, which, even if we do not create it ourselves, is created by default. Usually, creating an object looks like this (I will describe patterns using Java as an example):

MyClass object = new Myclass();

To prevent the creation of many objects, let's start by prohibiting the possibility of creating them at all. How to do it? It is enough that we will not be able to use the constructor, i.e. we will change the access modifier from public to private. Then our MyClass class will look like this:

public class MyClass {
    private static MyClass exampleObject;
    
    private MyClass() {}
}

Okay, but why do I need a class from which you can't create any object at all…. Well, now it's time to implement a very important basic mechanism for creating an object based on a static method in our class.

public class MyClass {
    private static MyClass exampleObject;
    
    private MyClass() {}

    public static MyClass getExampleObject(){
         if (exampleObject == null) {
            exampleObject = new MyClass();
        }
        return exampleObject;
    }
}

The conditional statement tells us that if an object has been created, the method will return a ready, previously created object, and if it has not been created, it will create it. To use a class created in this way, it should be called through a static method as follows:

MyClass object = Myclass.getExampleObject();

At this point, it can already be said that the pattern has been implemented. To test it, we will implement additional methods in our class that increment the number, and then we will try to create several objects of our class and call the method of incrementing the number on them. Our class will be as follows:

public class MyClass {
    private static MyClass exampleObject;
    private int number;

    private MyClass() {
        number = 0;
    }

    public static MyClass getExampleObject() {
        if (exampleObject == null) {
            exampleObject = new MyClass();
        }
        return exampleObject;
    }

    public void incrementNumber() {
        number++;
    }

    public int getNumber() {
        return number;
    }
}

Now let's use the created class as follows:

public class Main {

    public static void main(String[] args) {

        MyClass objectOne = MyClass.getExampleObject();
        System.out.println("Wartosc z obiektu 1 wynosi " + objectOne.getNumber());
        objectOne.incrementNumber();
        System.out.println("Wartosc z obiektu 1 wynosi " + objectOne.getNumber());

        MyClass objectTwo = MyClass.getExampleObject();
        System.out.println("Wartosc z obiektu 2 wynosi " + objectTwo.getNumber());
        objectTwo.incrementNumber();
        System.out.println("Wartosc z obiektu 2 wynosi " + objectTwo.getNumber());
    }
}

The program returns the following values:

Wartosc z obiektu 1 wynosi 0
Wartosc z obiektu 1 wynosi 1
Wartosc z obiektu 2 wynosi 1
Wartosc z obiektu 2 wynosi 2

The first call to object 1 creates an object for us, and then the incerementNumber () method performs an operation on the number. Trying to create a second object means that we do not get a new object with a zero value, but assign to the objectTwo object in fact the same object as in the case of objectOne. This solution makes it possible to easily use the same object in different places in the application, which significantly facilitates the creation of more flexible software.

Example of use

As an example, I wrote a simple console game where the application generates a random number from a set range. The user's task is to guess this number and enter it into the terminal. The game continues until the user guesses the drawn number. Then the application displays an appropriate message and indicates how many errors were made before the user correctly guessed the number.

The Zgadula class was created first. All application logic is stored in it. The class looks like this:

package com.company;

import java.util.Random;

public class Zgadula {
    private final int randomNumber;
    private boolean win;

    //podaj minimalną i maksymalną liczbę z zakresu z którego ma być wylosowana liczba.
    public Zgadula(int min, int max) {
        win = false;
        Random random = new Random();
        randomNumber = random.nextInt(max - min + 1) + min;
    }

    //zwraca wylosowaną liczbę
    public int getRandomNumber() {
        return randomNumber;
    }

    public boolean isWin() {
        return win;
    }


    //sprawdza czy podana liczba jest tą wylosowaną
    public void checkNumber(int number) {
        if (this.randomNumber == number) win = true;
        else {
            LicznikBledow licznik = LicznikBledow.getLicznik();
            licznik.addMistake();
        }
    }
}

The constructor of this class takes two values: maximum and minimum from the range from which the number is to be drawn, and then assigns these values to the variable randomNumber. Two other methods are helper methods, but let's pay attention to the last method, checkNumber.

This method checks if the number given by the user is the same as the number randomNumber. If the number is correct then the wine flag is set to true. Otherwise, the counter object calls addMistake (). Note how the counter object is declared. Through the static method of the CounterBledow class. Note that the object is created only when the user makes a mistake. Let's move on to this class of the Bledow Counter, and it looks like this:

package com.company;

public class LicznikBledow {
    private static LicznikBledow licznik;
    private int numberOfMistakes;

    //prywatny konstruktor uniemożliwiający utworzenie nowego obiektu wprost
    private LicznikBledow() {
        numberOfMistakes = 0;
    }

    //metoda statyczna, która tworzy i kontroluje ilość obiektów i ogranicza je do 1
    public static LicznikBledow getLicznik() {
        if (licznik == null) {
            licznik = new LicznikBledow();
        }
        return licznik;
    }

    //inkrementuje ilosc bledow
    public void addMistake() {
        numberOfMistakes++;
    }

    //zwraca ilosc bledow
    public int getNumberOfMistakes() {
        return numberOfMistakes;
    }
}

The most important in this class is the constructor, which is private, and the static method getCounter (), which controls the creation and return of the counter object. Right here we have implemented the singleton pattern. It is not possible to create more than one error counter (although that's not entirely true, but more on that later). Okay, but the question may arise why use this design pattern if you could create a regular Bledow Counter class with a public constructor if we only refer to the counter object once in the Guess class and declare it as follows:

package com.company;

public class LicznikZwykly {
    private int numberOfMistakes;

    //klasyczny publiczny konstruktor
    public LicznikZwykly() {
        numberOfMistakes = 0;
    }

    //inkrementuje ilosc bledow
    public void addMistake() {
        numberOfMistakes++;
    }

    //zwraca ilosc bledow
    public int getNumberOfMistakes() {
        return numberOfMistakes;
    }
}

The code is shorter, simpler and seems cleaner. The answer can be seen when we implement our main to create the Zgadula class object. So, let's go:

package com.company;

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Zgadula zgadula = new Zgadula(2, 6);
        Scanner scanner = new Scanner(System.in);

        while (!zgadula.isWin()) {
            System.out.println("Podaj liczbe: ");
            zgadula.checkNumber(scanner.nextInt());
        }

        LicznikBledow licznik = LicznikBledow.getLicznik();
        System.out.println("BRAWO! Szukana liczba to " + zgadula.getRandomNumber());
        System.out.println("Popelniles " + licznik.getNumberOfMistakes() + " bledow.");
    }
}

After creating the object guessing and scanner for the purposes of reading data to the console, a loop was saved, which is broken only after the correct guessing of the drawn number. And now let's pay attention to the line:

LicznikBledow licznik = LicznikBledow.getLicznik();

It looks like creating a new object based on the CounterBledow class through a static method, but in fact we assign to the value a counter already created in the Guesses class to the object with information about the number of errors made during the game. An example game turn in the console then looks like this:

Podaj liczbe: 
2
Podaj liczbe: 
3
Podaj liczbe: 
4
Podaj liczbe: 
5
BRAWO! Szukana liczba to 5
Popelniles 3 bledow.

Notice how easy it is to refer to the previously created object based on the CounterBledow class. In this way, you can implement further classes, such as the menu of this application, where you could display, for example, the number of errors from the previously played round of the game. In the new class, we would create a new object to which we would actually reassign the previously created object via the static method. But it's simple and convenient, isn't it?

Summary

The wisely used singleton pattern can significantly make the programmer's work easier and simplify the application code. At one point I mentioned that despite the use of a mechanism that prevents the creation of more objects, this can happen. This can happen if the application is multi-threaded, then there is a risk of creating 2 or more singletons simultaneously. There are ways to prevent this, but it is a topic for a separate article that may be written one day.

I hope that I have introduced as much as possible the ideas of this simple but very useful template and maybe someone will get a revelation and will be convinced of its use in their application.

W celu świadczenia usług na najwyższym poziomie stosuję pliki cookies, które będą zamieszczane w Państwa urządzeniu (komputerze, laptopie, smartfonie). W każdym momencie mogą Państwo dokonać zmiany ustawień Państwa przeglądarki internetowej i wyłączyć opcję zapisu plików cookies. Ze szczegółowymi informacjami dotyczącymi cookies na tej stronie można się zapoznać tutaj: View more
Cookies settings
Akceptuj
Blokuj
Privacy policy
Privacy & Cookies policy
Cookie name Active

The privacy policy describes the rules for the processing of information about you, including personal data and cookies, i.e. cookies.


1. General information

  1. This policy applies to the website operating at the url address: www.wojciechsiwek.pl
  2. The website operator and the personal data administrator is: Wojciech Siwek
  3. The operator's e-mail contact address: wojciech.siwek.programista@gmail.com
  4. The operator is the Administrator of your personal data in relation to the data provided voluntarily on the Website.
  5. The website uses personal data for the following purposes:
    • Running a comment system
    • Handling inquiries via the form
  6. The website obtains information about users and their behavior in the following way:
    1. Through data entered voluntarily in forms, which are entered into the Operator's systems.
    2. By saving cookie files in end devices (so-called "cookies").

2. Selected data protection methods used by the Operator

  1. The places of logging in and entering personal data are protected in the transmission layer (SSL certificate). As a result, personal data and login data entered on the website are encrypted on the user's computer and can only be read on the target server.
  2. User passwords are stored in a hashed form. The hash function works in one direction - it is not possible to reverse its operation, which is now a modern standard in the field of storing user passwords.
  3. The operator periodically changes his administrative passwords.
  4. In order to protect data, the Operator regularly makes backup copies.
  5. In order to protect data, an essential element of data protection is regular updating of all software used by the Operator to process personal data, which in particular means regular updates of programming components. The Operator regularly makes backup copies.

3. Hosting

  1. The website is hosted (technically maintained) on the operator's server: NETMARK.

4. Your rights and additional information on how to use the data

  1. In some situations, the Administrator has the right to transfer your personal data to other recipients if it is necessary to perform the contract concluded with you or to fulfill the obligations incumbent on the Administrator. This applies to such groups of recipients:
    • postal operators
    • comment system operators
    • authorized employees and associates who use the data to achieve the purpose of the website
  2. Your personal data processed by the Administrator for no longer than it is necessary to perform the related activities specified in separate regulations (e.g. on accounting). With regard to marketing data, the data will not be processed for more than 3 years.
  3. You have the right to request from the Administrator:
    • access to your personal data,
    • rectifying them,
    • deletion,
    • processing restrictions,
    • and data portability.
  4. You have the right to object to the processing indicated in point 3.3 c) to the processing of personal data in order to perform the legitimate interests pursued by the Administrator, including profiling, while the right to object may not be exercised if there are valid legally justified grounds for processing of your interests, rights and freedoms, in particular establishing, investigating or defending claims.
  5. The Administrator's actions may be appealed against to the President of the Personal Data Protection Office, ul. Stawki 2, 00-193 Warsaw.
  6. Providing personal data is voluntary, but necessary to operate the Website.
  7. In relation to you, actions may be taken consisting in automated decision making, including profiling to provide services under the concluded contract and for the purpose of conducting direct marketing by the Administrator.
  8. Personal data is not transferred from third countries within the meaning of the provisions on the protection of personal data. This means that we do not send them outside the European Union.

5. Information in the forms

  1. Serwis zbiera informacje podane dobrowolnie przez użytkownika, w tym dane osobowe, o ile zostaną one podane.
  2. The website may save information about connection parameters (time stamp, IP address).
  3. The website, in some cases, may save information facilitating the linking of data in the form with the e-mail address of the user filling in the form. In this case, the user's e-mail address appears inside the url of the page containing the form.
  4. The data provided in the form is processed for the purpose resulting from the function of a specific form, eg to process the service request or commercial contact, service registration, etc. Each time the context and description of the form clearly informs what it is used for.

6. Administrator logs

  1. Information on the behavior of users on the website may be subject to logging. These data are used to administer the website.

7. Relevant marketing techniques

  1. The operator uses statistical analysis of website traffic through Google Analytics (Google Inc. based in the USA). The operator does not provide personal data to the operator of this service, but only anonymised information. The service is based on the use of cookies on the user's end device. In terms of information about user preferences collected by the Google advertising network, the user can view and edit information derived from cookies using the tool: https://www.google.com/ads/preferences/

8. Information about cookies

  1. The website uses cookies.
  2. Cookie files (so-called "cookies") are IT data, in particular text files, which are stored on the Website User's end device and are intended for using the Website's pages. Cookies usually contain the name of the website they come from, the storage time on the end device and a unique number.
  3. The entity that places cookies on the Website User's end device and obtains access to them is the Website operator.
  4. Cookies are used for the following purposes:
    1. maintaining the Website user's session (after logging in), thanks to which the user does not have to re-enter the login and password on each subpage of the Website;
    2. achieving the goals set out above in the section "Important marketing techniques";
  5. The Website uses two basic types of cookies: session cookies and persistent cookies. Session cookies are temporary files that are stored on the User's end device until logging out, leaving the website or turning off the software (web browser). Persistent cookies are stored on the User's end device for the time specified in the cookie file parameters or until they are deleted by the User.
  6. Software for browsing websites (web browser) usually allows cookies to be stored on the User's end device by default. Website Users can change the settings in this regard. The web browser allows you to delete cookies. It is also possible to automatically block cookies.Detailed information on this subject can be found in the help or documentation of the web browser.
  7. Restrictions on the use of cookies may affect some of the functionalities available on the Website pages.
  8. Cookies placed on the Website User's end device may also be used by entities cooperating with the Website operator, in particular the following companies: Google (Google Inc. based in the USA), Facebook (Facebook Inc. based in the USA), Twitter (Twitter Inc. based in the USA).

9. Managing cookies - how to express and withdraw consent in practice?

  1. If the user does not want to receive cookies, he may change the browser settings. We reserve that disabling cookies necessary for authentication processes, security, maintaining user preferences may make it difficult, and in extreme cases may prevent the use of websites.
  2. In order to manage cookie settings, select the web browser you use from the list below and follow the instructions:
Save settings
Cookies settings