Você está na página 1de 33

Padrão de software –

singleton e strategy
Padrão de projeto de software

 Padrões de projeto (design patterns) são soluções típicas para problemas


comuns em projeto de software.

 Cada padrão é como uma planta de construção que você pode customizar
para resolver um problema de projeto particular em seu código (Refactoring
Guru, 2023)

 Um padrão não é uma técnica de programação, mas sim uma forma de


estruturar as ideias de programação a partir de modelos pré-definidos.

 Contribui para a obtenção da qualidade de projetos de software.


Padrão de projeto de software

 Estabelecido em 1994, por meio do livro Padrões de


Projeto — Soluções Reutilizáveis de Software Orientado
a Objetos

 Quatro autores: Erich Gamma, John Vlissides, Ralph


Johnson, e Richard Helm

 Gangue dos Quatro (Gang of Four): livro GoF.


Classificação dos padrões
Pra que aprender padrões de projeto?

 Os padrões de projeto são um kit de soluções testadas e aprovadas para


resolução de problemas comuns em projeto de software.

 Os padrões de projeto definem uma linguagem comum que você e seus


colegas podem usar para se comunicar mais eficientemente.

 Torna mais fácil o reuso de soluções e arquiteturas já validadas e testadas


para construção de softwares de forma flexível

 De acordo com a finalidade do software e o escopo existe um conjunto de


boas práticas que evitam erros comuns
O que tem em um padrão?

 O Propósito do padrão descreve brevemente o problema e a solução


(Refactoring guru, 2023).

 A Motivação explica a fundo o problema e a solução que o padrão torna


possível.

 As Estruturas de classes mostram cada parte do padrão e como se


relacionam.

 Exemplos de código em uma das linguagens de programação populares


tornam mais fácil compreender a ideia por trás do padrão.
Exemplo

 Criar uma classe que permita a implementação de uma calculadora

 Porque foram utilizadas as soluções aplicadas?

 Existe alguma chance de erro de execução ou de dificuldade de manutenção


da implementação?

 O formato aplicado é algo de fácil compreensão à outros programadores e


envolvidos?
Como usar um design pattern?

 Primeiro estabelecer os objetivos da busca pelo padrão mais indicado


 Pode ser a organização do código ou um problema de execução

 Verificar se o objetivo é comportamental, estrutural ou de criação

 Identificar aqueles mais indicados à solução

 Estudar o padrão completo e validar a aplicabilidade e consequências da


aplicação dos design pattern
Princípios SOLID

 Princípios de orientação à objeto

 Os 5 princípios da POO
 S — Single Responsiblity Principle (Princípio da responsabilidade única)
 O — Open-Closed Principle (Princípio Aberto-Fechado)
 L — Liskov Substitution Principle (Princípio da substituição de Liskov)
 I — Interface Segregation Principle (Princípio da Segregação da Interface)
 D — Dependency Inversion Principle (Princípio da inversão da dependência)
Princípios SOLID

 1. SRP - Princípio da Responsabilidade Única


 Uma classe deve ter um, e somente um, motivo para mudar.
 Uma classe deve ser especializada e ter uma única tarefa para executar

 2. OCP - Princípio Aberto-Fechado


 Entidades devem estar abertos para extensão, mas fechados para modificação
 Pode-se colocar funcionalidades, mas não alterar as que já existem

 3. LSP - Princípio da substituição de Liskov


 Uma classe derivada deve ser substituível por sua classe base
 Pode-se substituir as superclasses pelas subclasses sem problemas na implementação
Princípios SOLID

 4. ISP - Princípio da Segregação da Interface


 Uma classe não deve ser forçada a implementar interfaces e métodos que não irão
utilizar.
 As interfaces não podem ser genéricas com métodos que não serão usados

 5. DIP - Princípio da Inversão de Dependência


 Dependa de abstrações e não de implementações.
 O que importa é a ideia, não o código
Padrão de Projeto Singleton

 Garante que uma classe possuirá apenas uma única instância

 Uma classe irá gerar apenas um objeto que estará disponível em todo domínio
da aplicação

 Interessante em casos que a existência de mais de uma instancia pode gerar


erros de execução da aplicação
 Disputa de recursos ou deadlocks
 Objetos que realizam operações sem a manutenção de estados individuais

 Ótimo para aplicação em processos de sincronização de execução


Vantagens

 O Padrão Singleton permite a criação de classes que podem ser instanciadas e


usada apenas quando necessário

 Garantir que apenas uma instância exista na aplicação

 Não existem cópias redundantes da classe


 Memória sem réplicas desnecessárias

 Atributos globais porém encapsulados

 Acesso aos métodos e atributos de modo único e global


Desvantagens

 Acoplamento dos código à atributos e métodos estáticos

 Falsa sensação de segurança em algumas linguagens de programação

 Quebra dos princípios SOLID;

 Falta de rastreabilidade;

 Dificulta na implementação de testes;

 Sacrifica transparência, por conveniência.


Funcionamento

 Oferece um ponto de acesso global, porém sem desvantagens das variáveis globais
 Valores globais (estáticos) mas sem vazamento de dados

 A classe deve gerenciar a própria instância dela para evitar que outras instancias sejam
criadas
 A classe armazena a referência de sua instância

 Preocupação com execuções paralelas


 Uso de volatile ou synchronized no Java

 Os métodos devem ser estáticos e públicos

 Os atributos devem ser estáticos e provados


Estrutura de um singleton

 Uma variável estática privada, que contém a única instância da classe.

 Um construtor privado, de modo a não ser possível instanciá-la de qualquer


outro lugar.

 Um método estático público, para retornar a instância única da classe.


Exemplo
public static No getInstance(double valor) {
public class No {
if (instancia == null) {
instancia = new No(valor);
private double valor;
}
private volatile static No instancia;
return instancia;
}
private No(double valor) {
this.valor = valor;
public double getValor() {
}
return this.valor;
}
}
Exemplo 2 – Comparar os resultados de
execução de 2 threads com e sem Singleton

class Main {
public static void main(String[] args) {
SemSingleton s01 = new SemSingleton("t001");
SemSingleton s02 = new SemSingleton("t002");

Singleton sg1 = Singleton.getInstance("teste001");


try {
Thread.sleep(100); //alterar o valor do sleep para verificar a sequencia de execução }
catch (InterruptedException ex) {}
Singleton sg2 = Singleton.getInstance("teste002");
}
}
import javax.swing.Timer;

public class SemSingleton implements Runnable{


private String mensage;
private Thread t;
public SemSingleton(String msg) {
this.mensage = msg;
start();
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1);
System.out.println(mensage);
} catch (InterruptedException ex) {}
} }

public void start(){


t = new Thread (this, mensage);
t.start();
}
}
public class Singleton implements Runnable{
private static Singleton sg;
private static String mensage;
private static Thread t;
private Singleton(String msg) {
mensage = msg;
start();
}
public static Singleton getInstance(String msg){
if (sg == null) {
sg = new Singleton(msg); }
return sg;
}
public static void setMsg(String msg) { mensage = msg; }
public static String getMsg(){ return mensage; }
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1);
System.out.println(mensage);
} catch (InterruptedException ex) {} }
sg = null; }

public void start(){


t = new Thread (this, mensage);
t.start();
}
}
Padrão de Projeto Strategy

 O Strategy é um padrão de projeto comportamental que transforma um


conjunto de comportamentos em objetos e os torna intercambiáveis dentro
do objeto de contexto original.

 Foco na construção de interfaces para encapsular um conjunto de algoritmos


com aplicação semelhante
 Criar uma família de implementações intercambiáveis

 Aplicação de polimorfismo e especialização

 Não importa as implementações, apenas as chamadas dos métodos


Vantagens do Strategy

 Flexibilidade: permite que o comportamento de um objeto seja alterado em


tempo de execução.

 Modularidade: O padrão encapsula os algoritmos em classes separadas, isolando


implementações e modificações.

 Testabilidade: permite testar diferentes algoritmos separadamente, sem afetar o


comportamento do código.

 Princípio Aberto-Fechado: O padrão Estratégia segue o Princípio Aberto-Fechado,


que afirma que uma classe deve ser aberta para extensão, mas fechada para
modificação.
Desvantagens do Strategy

 Aumento da complexidade devido ao uso de múltiplas classes

 Possíveis problemas de desempenho por conta da seleção de algoritmos em


tempo de execução.

 Reutilização de código e duplicidade de implementações


Componente de um Strategy

 A interface Strategy é responsável por estabelecer um tipo de contrato


(interface).

 O Concret Strategy é a classe concreta que irá implementar a interface


Strategy.

 A classe Context tem como responsabilidade armazenar uma instância do tipo


Strategy, chamar a função abstrata da interface e conseguir trocar objetos do
tipo Strategy, se requisitado.
Melhores práticas
(https://www.freecodecamp.org/)
 Identifique o algoritmo ou comportamento que precisa ser encapsulado e
tornado intercambiável.
 Defina uma interface que represente o comportamento, com uma única
assinatura de método que aceita quaisquer parâmetros necessários.
 Implemente classes concretas que forneçam implementações específicas do
comportamento definido na interface.
 Defina uma classe de contexto que contenha uma referência à interface e
chame seu método quando necessário.
 Modifique a classe de contexto para permitir a troca dinâmica das
implementações concretas em tempo de execução.
Exemplo Strategic

public static void main(String[] args) {

Transporte tr = new Carro(10);


Transporte tr2 = new Bike();

System.out.println(tr.custoTransporte(100));
System.out.println(tr2.custoTransporte(100));
}
Exemplo II Strategic

public interface Transporte { public class Carro implements Transporte{


public String tipoTransporte();
private double teste;
public double custoTransporte(int km);
public Carro (double teste) {
}
this.teste = teste;
}

public double getTeste() { return this.teste; }

@Override
public String tipoTransporte() { return "Carro"; }

@Override
public double custoTransporte(int km) { return km*10; }

}
Tipo enum como meio de aplicar o
Strategic
 Um tipo enum é um tipo de campo que define um conjunto fixo de constantes
(static final), sendo como uma lista de valores pré-definidos

 É possível utilizar o enum como meio para implementar o Strategic

 O tipo enum será a interface, com as implementações internas à coleção


Enum Java
public enum nomes2 {
//constantes e inicialização dos valores
public enum nomes {b1, b2, b3}; B1(1,10),
B2(2,20),
B3(3,30);

private int valor;


private int valor2;

nomes2(int valor, int valor2) {


this.valor = valor;
}
public int getvalor() {
return this.valor;
}
}
Enum Java

public enum nomes {b1, b2, b3}; public enum nomes2 {


//constantes e inicialização dos valores
B1(1,10),
B2(2,20),
B3(3,30);

private int valor;


private int valor2;

nomes2(int valor, int valor2) {


this.valor = valor;
}
public int getvalor() {
return this.valor;
}
}
Enum Java

enum nomes3 {
B1 {
public int constante() { return 11;}
},
B2 {
public int constante() { return 22;}
},
B3 {
public int constante() { return 33;}
};

public abstract int constante();


}
Exemplo Strategic Enum
public static void main(String[] args) {

nomes3 n3 = nomes3.B1;
System.out.println(n3.constante());

nomes2 n2 = nomes2.B3;
System.out.println(n2.getvalor());

for (int i = 0; i < 3; i++) {


System.out.println(i + "----" + nomes.values()[i]);
}
for (nomes n1 : nomes.values()) {
System.out.println("+++" + n1);
}
for (nomes n1 : nomes.values()) {
System.out.println(n1.ordinal() + "+++" + n1);
}
nomes op = nomes.b1;
System.out.println("----" + op);
if (op.equals(nomes.b3)) {
System.out.println("oi");
}
}
Exemplo Strategy II Enum

public enum ImpostoTipo {

NORMAL{
@Override
double calcularImposto(double preco) { return preco * 0.2; } },

IDOSOS{
@Override
double calcularImposto(double preco) { return preco * 0.1; } },

ESTUDANTES{
@Override
double calcularImposto(double preco) { return preco * 0.15; } };

abstract double calcularImposto(double preco);

Você também pode gostar