Método Singleton

Estou com dificuldades de desenvolver o programa em Java usando o método Singleton, pesquisei mas não ficou claro em como criar os objetos desejados.

O enunciado da questão é o seguinte:

  1. Implemente uma “Fábrica” de figuras geométricas a partir da qual é possível criar um único círculo, três instâncias de triângulos (um isósceles, um equilátero e um retângulo) e inúmeros quadrados.

Fiz as seguintes partes do código, mas não estou sabendo como ir em frente. Peço perdão, pois sei que aqui é um espaço para tirar dúvidas pontuais. Mas, solicito a compreensão tendo em vista o afastamento que estamos tendo com os professores e impossibilidade de se tirar dúvidas. A maior problemática que estou encontrando é a falta de exemplos usando este método para poder me basear e resolver meu trabalho.

Criei a o método Singleton Fabrica...

public class Fabrica {
	
	private static Fabrica instanciaUnica = null;
	
	private Fabrica() {
		
	}
	
	public static Fabrica getInstance() {
		if(instanciaUnica == null) {
			instanciaUnica = new Fabrica();
		}
		return instanciaUnica;
	}

}

Pelo material que pesquisei vi, que se deve criar interfaces para posteriormente criar as classes. Acontece que os métodos que devo desenvolver são mais complexos que os exemplos que vi. Agradeço desde já qualquer ajuda.

public interface Forma {
	
	public int area();
	
	public int perimetro();

}


Singleton é um padrão de projeto, não um método.
Se sua classe Fabrica está seguindo o padrão Singleton, então você obtém a instância da Fabrica dessa forma:

Fabrica objetoDaFabrica = Fabrica.getInstance();

Obrigado!
Gostaria de entender como construo as classes e os métodos para usar…

Quais classes e quais métodos?

  1. Implemente uma “Fábrica” de figuras geométricas a partir da qual é possível criar um único círculo, três instâncias de triângulos (um isósceles, um equilátero e um retângulo) e inúmeros quadrados.

Fiz o programa, mas a professora disse que estava errado. Que era para usar o método apenas no circulo. Não entendi…
Qual a melhor forma de se usar o método Sigleton para o problema dado, não estou compreendendo como fazer.

Segue o programa:


public class Fabrica {

	private static Fabrica factoryInstance = null;
	
	private Fabrica() {
		
	}
	
	public static Fabrica getInstance() {
		if(factoryInstance == null) {
		   factoryInstance = new Fabrica();
		}
		return factoryInstance;
	}
	
	
	public void getCirculo() {
		Circulo circulo = new Circulo();
		circulo.area();
		circulo.perimetro();
		System.out.println("Circulo [area()=" + circulo.area() + ", perimetro()=" + circulo.perimetro() + "]");
	}
	
	public void getQuadrados(int lado1, int lado2) throws notIsSquareException {
		Quadrados quadrados = new Quadrados(lado1, lado2);
		quadrados.area();
		quadrados.perimetro();
		System.out.println("Quadradros [area()=" + quadrados.area() + ", perimetro()=" + quadrados.perimetro() + "]");
	}
	
	public void getTriangle(double side1, double side2, double side3) throws TriangleException {
		Triangle triangle = new Triangle(side1, side2, side3);
		System.out.println(triangle.getKind());
	}

}


public class Circulo implements Forma{
    int raio;
	
	public Circulo() {
		this.raio = 5;
	}

	@Override
	public int area() {
		return (int) (Math.PI *  Math.pow(raio, 2));
	}

	@Override
	public int perimetro() {		
		return (int) (2 * Math.PI * raio);
	}
	
}

import java.util.HashSet;
import java.util.Set; 
 
public class Triangle { 
 
    private double side1; 
    private double side2; 
    private double side3; 
 
    public Triangle(double side1, double side2, double side3) throws TriangleException { 
        this.side1 = side1; 
        this.side2 = side2; 
        this.side3 = side3; 
 
        if (allSidesAreZero() || hasImpossibleSides() || violatesTriangleInequality()) { 
            throw new TriangleException(); 
        } 
    } 
 
    public TriangleKind getKind() { 
        int uniqueSides = getNumberOfUniqueSides(); 
 
        if (uniqueSides == 1) { 
            return TriangleKind.EQUILATERAL; 
        } 
 
        if (uniqueSides == 2) { 
            return TriangleKind.ISOSCELES; 
        } 
 
        return TriangleKind.SCALENE; 
    } 
 
    private boolean allSidesAreZero() { 
        return side1 == 0 && side2 == 0 && side3 == 0; 
    } 
 
    private boolean hasImpossibleSides() { 
        return side1 < 0 || side2 < 0 || side3 < 0; 
    } 
 
    private boolean violatesTriangleInequality() { 
        return side1 + side2 <= side3 || side1 + side3 <= side2 || side2 + side3 <= side1; 
    } 
  
    public int getNumberOfUniqueSides() { 
        Set<Double> sides = new HashSet<>(); 
 
        sides.add(side1); 
        sides.add(side2); 
        sides.add(side3); 
 
        return sides.size(); 
    } 
}

@SuppressWarnings("serial")
public class TriangleException extends Exception {
	 
    public TriangleException() { 
    	
    } 
}


public enum TriangleKind {
	EQUILATERAL, ISOSCELES, SCALENE
}

public class FabricaExecutor {

	public static void main(String[] args) throws notIsSquareException, TriangleException {
		 Fabrica fabrica = Fabrica.getInstance();
		 
		 fabrica.getCirculo();
		 
		 fabrica.getQuadrados(2, 2);
		 fabrica.getQuadrados(4, 4);
		 fabrica.getQuadrados(6, 6);
		 
		 fabrica.getTriangle(2, 2, 2);  //Equilátero
		 fabrica.getTriangle(5, 5, 3);  //Isocesles
		 fabrica.getTriangle(6, 4, 3);  //Escaleno

	}

}


public class Quadrados implements Forma {

	int lado1, lado2;

	public Quadrados(int lado1, int lado2) throws notIsSquareException {
		this.lado1 = lado1;
		this.lado2 = lado2;

		if (allSidesAreDiferents()|allSidesAreZero()) {
			throw new notIsSquareException();
		}
	}
	
	   private boolean allSidesAreDiferents() { 
	        return lado1 != lado2; 
	    } 
	
	   private boolean allSidesAreZero() { 
	        return lado1 == 0 && lado2 == 0; 
	    } 

	@Override
	public int area() {
		return lado1 * lado2;
	}

	@Override
	public int perimetro() {
		return 2 * lado1 + 2 * lado2;
	}

	@Override
	public String toString() {
		return "Quadradros [area()=" + area() + ", perimetro()=" + perimetro() + "]";
	}
}


Também tenho dúvidas com os testes se alguém puder me orientar como fazê-los da melhor forma...


public class Quadrados implements Forma {

	int lado1, lado2;

	public Quadrados(int lado1, int lado2) throws notIsSquareException {
		this.lado1 = lado1;
		this.lado2 = lado2;

		if (allSidesAreDiferents()|allSidesAreZero()) {
			throw new notIsSquareException();
		}
	}
	
	   private boolean allSidesAreDiferents() { 
	        return lado1 != lado2; 
	    } 
	
	   private boolean allSidesAreZero() { 
	        return lado1 == 0 && lado2 == 0; 
	    } 

	@Override
	public int area() {
		return lado1 * lado2;
	}

	@Override
	public int perimetro() {
		return 2 * lado1 + 2 * lado2;
	}

	@Override
	public String toString() {
		return "Quadradros [area()=" + area() + ", perimetro()=" + perimetro() + "]";
	}
	
	

}

import org.junit.Assert;
import org.junit.jupiter.api.Test;

class QuadradosTest {

	@Test
	void testAcertaArea() throws notIsSquareException {
		// Arrange
		Quadrados quadrado = new Quadrados(4, 4);		
		quadrado.perimetro();

		// Act
		int actual = quadrado.area();	
		
		// Assert
		Assert.assertEquals(16, actual);
	}
	
	@Test
	void testErraArea() throws notIsSquareException {
		// Arrange
		Quadrados quadrado = new Quadrados(4, 4);
	
    	// Act
		int actual =quadrado.area();

		// Assert
		Assert.assertNotEquals(17, actual);
	}

	@Test
	void testAcertaPerimetro() throws notIsSquareException {
		// Arrange
		Quadrados quadrado = new Quadrados(4, 4);
		
		// Act
		int actual = quadrado.perimetro();		
		
		// Assert
		Assert.assertEquals(16, actual);
	}
	
	@Test
	void testErraPerimetro() throws notIsSquareException {
		// Arrange
		Quadrados quadrado = new Quadrados( 4, 4);
		
		// Act
		int actual = quadrado.perimetro();
		
		// Assert
		Assert.assertNotEquals(15, actual);
	}

}

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class FabricaTest {

	@Test
	public void testObjectEquality() {
		// Arrange
		Fabrica instance1 = Fabrica.getInstance();
		Fabrica instance2 = Fabrica.getInstance();

		// Assert
		assertNotNull(instance1);
		assertNotNull(instance2);
		assertEquals(instance1, instance2);
	}

	@Test
	public void testDataEquality() {
		// Arrange
		Fabrica instance1 = Fabrica.getInstance();
		Fabrica instance2 = Fabrica.getInstance();

		// Assert
		assertNotNull(instance1);
		assertNotNull(instance2);
		assertEquals(instance1, instance2);
	}

	@Test
	public void testFabricaSingleton() {
		// Arrange
		Fabrica singleton = Fabrica.getInstance();

		// Assert
		assertNotNull(singleton);
		// Check that the singleton is a BruteForceSubclassSingleton.
		assertTrue(singleton instanceof Fabrica);
	}

	@Test
	public void testFabricaSingletonsTrue() {
		// Arrange
		Fabrica singleton = Fabrica.getInstance();
		Fabrica singleton2 = Fabrica.getInstance();

		// Assert
		assertNotNull(singleton);
		assertTrue(singleton instanceof Fabrica);
		assertNotNull(singleton2);
		assertTrue(singleton2 instanceof Fabrica);
	}

	@Test
	public void testFabricaSingletonsNot() {
		// Arrange
		Fabrica singleton = Fabrica.getInstance();
		Fabrica singleton2 = Fabrica.getInstance();

		// Assert
		assertNotNull(singleton);
		assertFalse(singleton instanceof Fabrica);
		assertNotNull(singleton2);
		assertFalse(singleton == singleton2);
	}
	
	
	

}

Se ela disse isso, então é para a classe Circulo ser um Singleton e não a classe Fabrica.

Outra coisa, os métodos get da sua Fabrica estão com o retorno void, está errado, eles deveriam retornar o objeto que criam e não void.

Entendi, obrigado!

Com relação aos testes, você tem algo a falar?

A Classe Fabrica preciso mudar?
Ela não deixou claro…

Há um outro problema que preciso resolver, a classe triângulo também é singleton.
Fiz as instâncias para cada triângulo, mas tenho dúvida em como usar…

Não é não, seu enunciado diz claramente que serão criadas 3 instâncias de triângulo.
Uma classe Singleton permite somente uma instância.

Se ela continua igual ao código que você postou aqui, precisa mudar sim, pois os métodos da sua fábrica não retornam nada.
A ideia de uma fábrica é ter métodos que retornam os objetos que são “fabricados”.

1 curtida