19
loading...
This website collects cookies to deliver better user experience
if/else
assim:if(cerveja.getName() == "IPA"){
//faça algo
}else {
//faça outra coisa
}
if
ou então vou substituir por um block switch case
? As duas abordagens na verdade mascaram o mesmo problema que é o problema de sua implementação poder crescer infinitamente. Isso gera um código gigante, difícil de dar manutenção e difícil de entender e ainda mais existe um princípio que esse tipo de implementação fere que é o princípio Open/Close (Aberto/Fechado) do S.O.L.I.D. que diz: “entidades de software (classes, módulos, funções, etc.) devem ser abertas para extensão, mas fechadas para modificação”. Trocando em miúdos isso quer dizer que você ter várias extensões de uma interface, classe e etc. sem mudar nada neles. Mas como trazer isso pro nosso caso?package com.example.demo.beer;
public interface Beer {
void drink();
String label();
}
public class Ale implements Beer{
@Override
public void drink() {
System.out.println("Drink a ale beer");
}
@Override
public String label() {
return "Ale";
}
}
public class Test {
public void callCorrectBeer(){
Beer beer = new Ale();
beer.drink();
}
}
public class Main {
public static void main(String... args){
//dado de entrada
String beerAle = "Ale";
Beer beer = //de alguma forma eu descobrir que se trata de uma Ale
beer.drink();
}
}
package com.example.demo.beer.factory;
public interface AbstractFactory<T> {
T create(String type);
}
public class FactoryBeer implements AbstractFactory<Beer> {
@Override
public Beer create(String type) {
if(type == "Ale"){
return new Ale();
}if else(type == "Stout"){
return new Stout();
}else {
return Ipa();
}
}
}
if/else
de novo mas na verdade estamos deixando em um único ponto, que é na nossa classe especializada em fabricar objetos, mas podemos melhorar isso, nesse projeto eu uso Spring Boot e ele trabalha com o conceito de IoC (Inversão de Controle) e nos fornece uma interface que é a ApplicationContext que gerencia os nossos Beans , pra não entrar muito dentro dos detalhes a grosso modo tudo o que usar as annotations @Bean
, @Component
, @Controller
, @Service
, @Repository
, @Autowired
, e @Qualifier
serão objetos que o Spring vai gerenciar e ele é que vai decidir quando eles estarão disponíveis pra uso. Então depois de toda essa explicação é pra dizer que podemos então delegar essa responsabilidade pro ApplicationContext pra gente assim:@Component
public class FactoryBeer implements AbstractFactory<Beer> {
@Autowired
private ApplicationContext context;
@Override
public Beer create(String type) {
return context.getBean(type);
}
}
@Component
e isso faz com que automaticamente o Spring comece a gerenciar a injeção das nossas dependências, injetamos com a anotação @Autowired
a nossa interface ApplicationContext e no nosso método chamamos o getBean e ele vai trazer pra gente a instância certa. Só tem um problema aqui, caso seja passada uma String type errada que não exista ele vai lançar uma BeansException , inclusive o próprio método getBean faz parte da API da interface BeanFactory que é fábrica de Beans do Spring. Vamos então criar um jeito onde eu passe um tipo que existe e ele irá chamar o tipo existente, vamos criar uma enumeração Enum onde conseguimos registrar as nossas classes de serviço e um método de busca:public enum BeerType {
ALE("Ale", Ale.class),
IPA("Ipa", Ipa.class),
STOUT("Stout", Stout.class);
private String name;
private Class<? extends Beer> type;
BeerType(String name, Class<? extends Beer> type){
this.name = name;
this.type = type;
}
public static BeerType of(String value) {
return Arrays.stream(values()).filter(type -> type.name.equalsIgnoreCase(value)).findFirst().get();
}
public String getName() {
return name;
}
public Class<? extends Beer> getType(){
return type;
}
}
@Component
para ficar mais semântico. Então o resultado final da nossa factory ficaria assim:@Component
public class FactoryBeer implements AbstractFactory<Beer> {
@Autowired
private ApplicationContext context;
@Override
public Beer create(String type) {
return context.getBean(BeerType.of(type).getType());
}
}
@Service
public class BeerService {
@Autowired
private AbstractFactory<Beer> factory;
public void process(String beer) {
Beer beerBean = factory.create(beer);
beerBean.drink();
}
}
@SpringBootApplication
public class DemoApplication implements CommandLineRunner{
@Autowired
private BeerService service;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
service.process(BeerType.ALE.getName());
service.process(BeerType.IPA.getName());
service.process(BeerType.STOUT.getName());
}
}
Drink a ale beer
Drink a ipa beer
Drink a stout beer