5.1 Trabalhando com livros digitais
Por causa da sua praticidade e fácil portabilidade, muitos leitores preferem livros digitais (e-books) aos livros físicos. Nossa livraria não pode ficar para trás, portanto, passaremos a trabalhar com esse novo tipo de livro.
Mas, afinal, como podemos diferenciar um Livro impresso de um Ebook? Uma forma simples de fazer isso seria adicionando um atributo que define o tipo de livro. Poderia simplesmente ser um boolean, marcando se um livro é impresso ou não. Repare:
public class Livro {
java
private String nome; private String descricao; private double valor;
private String isbn; private Autor autor; private boolean impresso;
public Livro(Autor autor) { this.autor autor;
this.isbn "000-00-00000-00-0"; this.impresso true;
}
// outros metodos da classe
}
Note que em nosso construtor já definimos um valor padrão para o atrib-
uto impresso. Todo Livro que não tenha o valor de impresso definido será considerado um livro impresso.
Essa é uma forma simples de resolver o problema e talvez até possa atender bem as nossas necessidades, mas o problema dessa abordagem é que um Ebook tem alguns comportamentos bastante diferentes do que um livro impresso. Por exemplo, o método aplicaDescontoDe da classe Livro atualmente limita a porcentagem de desconto em 30%.
public boolean aplicaDescontoDe(double porcentagem) { if (porcentagem > 0.3) {return false;
}
this.valor - this.valor * porcentagem; return true;
}
Mas quando se trata de um Ebook, a regra é um pouco diferente: pode-
mos aplicar no máximo 15% de desconto. Podemos resolver esse problema adicionando mais uma condição ao método:
public boolean aplicaDescontoDe(double porcentagem) { if (porcentagem > 0.3) {return false;
} else if (!this.impresso && porcentagem > 0.15) { return false;
}
this.valor — this.valor * porcentagem; return true;
}
Agora nosso código funciona como esperado, mas está um pouco mais
verboso e difícil de entender. O grande problema aqui é que, a cada método cuja regra seja diferente, teremos que colocar um novo if parecido com esse, isso sem contar que novos tipos de Livro podem aparecer e tornar nosso código ainda mais complicado e cheio de condicionais. Devemos sempre escrever nosso código pensando em como será sua evolução no futuro.
Além disso, existem alguns comportamentos e atributos que só servem para um Ebook. Um deles é o watermark (marca d’água). Essa é a forma de identificar discretamente o nome e e-mail do dono daquele livro digital, normalmente no rodapé das páginas.
Se Ebook é um elemento importante, possui comportamentos e atributos específicos, ele deveria ser representado como um Objeto! Podemos criar uma classe Ebook definindo os atributos e comportamentos específicos desse novo tipo.
public class Ebook {
java
private String nome; private String descricao; private double valor; private String isbn; private Autor autor; private String waterMark;
java
public void setWaterMark(String waterMark) { this.waterMark - waterMark;}
public String getWaterMark() { return waterMark;}
// getters, setters e outros metodos
}
Nosso código já está um pouco mais interessante, afinal não estamos mais
sobrecarregando a classe Livro com atributos e métodos que serão utilizados apenas quando o tipo do livro for um ebook. Mas há muito código repetido aqui: além dos comportamentos do Ebook, temos todos os atributos e métodos já escritos na classe Livro.
Para evitar toda essa repetição de código, podemos ensinar ao compilador que o Ebook é um tipo de Livro, ou seja, além de seus próprios atributos e métodos, essa classe possui tudo o que um Livro tem. Para fazer isto, basta Ebook dizer na declaração da classe que ela é um Livro, queé uma extensão dessa classe:
public class Ebook extends Livro { private String waterMark;
java
public Ebook(Autor autor) { super(autor);
}
java
public void setWaterMark(String waterMark) { this.waterMark = waterMark;}
public String getWaterMark() { return waterMark;