You are on page 1of 46

Programação
em
Java
para
a
Plataforma
Android
–
AULA
20


Princípios
de
Projeto
de
Classes
‐
I

•  A
classe
como
unidade
de
reúso
de
código

•  Princípios
que
garantem
a
boa
práGca
da
programação
orientada
a
objetos

•  Princípio
da
Abertura‐Fechamento

•  Principio
da
SubsGtuição
de
Liskov

•  Programando
para
interfaces
genéricas

•  Antropomorfização
dos
dados.

O
que
é
uma
classe?

•  Menor
unidade
compilável
na
linguagem
Java

nor
Qual é a me
unidade
p i l á ve l e m C?
com

•  Implementação
de
um
Gpo
abstrato
de
dados


O que é um tipo
abstrato de
dados?
Princípios
de
Projeto
de
Classes

•  PráGcas
que
orientam
o
desenvolvedor
na

criação
de
melhores
projetos
de
classes.

–  Princípio
da
SubsGtuição
de
Liskov

–  Princípio
da
Abertura‐Fechamento

–  Princípio
da
Inversão
de
Dependências

–  Princípio
da
Segregação
de
Interfaces

O que é
O objetivo desses x t en si b i li d ade?
O que é reúso? e
princípios é
garantir reúso e
extensibilidade.
Reúso
de
SoVware

•  Reusar
um
módulo
de
soVware
significa

uGlizar
aquele
módulo
sem
que
seja

necessário
ter
acesso
a
seu
código
fonte.



Quais as
cas
característi
ulo
que um mód
e ve r i a te r para
d
l?
ser reusáve
Extensibilidade

•  Um
conjunto
de
módulos
é
extensível
quando

alterações
em
um
desses
módulos
não
leva
a

modificações
nos
outros.

•  Alterações
de
atualização:
a
implementação

de
um
módulo
é
alterada.

•  Alterações
de
expansão:
um
novo
módulo
é

adicionado
ao
conjunto.
 eral, lidar
Em g
m a e xp a n são é
co
Por
mais difícil.
que?
Princípio
da
SubsGtuição
de
Liskov

•  Em
qualquer
situação
em
que
se
espera
um

Gpo,
pode‐se
passar
um
subGpo.

public
interface
Shape
{



void
draw(Canvas
canvas,
Paint
paint);

}

public
class
Rectangle
implements
Shape
{
 public
class
Square
extends
Rectangle
{



private
int
x,
y,
w,
h;


 

public
Square(int
x,
int
y,
int
side)
{



public
Rectangle(int
nx,
int
ny,
int
nw,
int
nh)
{
 



super(x,
y,
side,
side);





x
=
nx;



}





y
=
ny;





w
=
nw;
 }





h
=
nh;



}
 Esse princípio aplica-se


public
void
draw(Canvas
canvas,
Paint
paint)
{
 naturalmente a linguagens que




canvas.drawRect(x,
y,
x
+
w,
y
+
h,
paint);
 possuem polimorfismo de


}

}
 subtipagem
SubGpagem
em
Ação

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeWindow shapeWindow =
new ShapeWindow(this, 180, 200);
Shape s0 = new Rectangle(0, 0, 100, 180);
shapeWindow.addShape(s0);
Shape s1 = new Square(90, 90, 50);
shapeWindow.addShape(s1);
}

Precisamos
r
implementa
essa visão.
ShapeWindow.java

public
class
ShapeWindow
extends
View
{



private
List<Shape>
shapes
=
new
ArrayList<Shape>();




public
ShapeWindow(Context
context,
final
int
width,
final
int
height)
{





super(context);


Janela
de
Formas





setFocusable(true);





setMinimumWidth(width);





setMinimumHeight(height);



}



protected
void
onMeasure(int
widthMeasureSpec,
int
heightMeasureSpec)
{





setMeasuredDimension(getSuggestedMinimumWidth(),









getSuggestedMinimumHeight());



}



public
void
addShape(Shape
shape)
{
this.shapes.add(shape);
}



protected
void
onDraw(Canvas
canvas)
{





Paint
paint
=
new
Paint();





paint.setStyle(Style.FILL);





paint.setColor(Color.WHITE);





canvas.drawRect(1,
1,
this.getWidth()
‐
1,
this.getHeight()
‐
1,
paint);





paint.setColor(Color.BLACK);





paint.setStyle(Style.STROKE);





for
(Shape
shape
:
shapes)
{
shape.draw(canvas,
paint);
}



}

}

Especialização

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeWindow shapeWindow =
new ShapeWindow(this, 180, 200);
Shape s0 = new Rectangle(0, 0, 100, 180);
shapeWindow.addShape(s0);
Shape s1 = new Square(90, 90, 50);
shapeWindow.addShape(s1);
Rectangle s2 = new Square(90, 90, 50);
shapeWindow.addShape(s2);
}
sa
Será que es
atribuição é
válida?
Generalização

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeWindow shapeWindow =
new ShapeWindow(this, 180, 200);
E essa
Shape s0 = new Rectangle(0, 0, 100, 180);
shapeWindow.addShape(s0); atribuição?
é
Shape s1 = new Square(90, 90, 50); Será que ela
shapeWindow.addShape(s1);
v álida?
Rectangle s2 = new Square(90, 90, 50);
shapeWindow.addShape(s2);
Square s3 = new Rectangle(10, 10, 30, 40);
shapeWindow.addShape(s2);
}
Compilador
guardai‐nos!

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeWindow shapeWindow =
new ShapeWindow(this, 180, 200);
esse s0 = new
Só que nShape SerRectangle(0,
á então 0, 100, 180);
possível
shapeWindow.addShape(s0);
caso o Shape s1 = new
g r a m a n ã o qu Square(90,
eb r ar P SL
90, 50);
pro shapeWindow.addShape(s1);
compila ! em Java?
Rectangle s2 = new Square(90, 90, 50);
shapeWindow.addShape(s2);
Square s3 = new Rectangle(10, 10, 30, 40);
shapeWindow.addShape(s2);
}
Quebrando
PSL
em
Java

public
class
Rectangle
implements
Shape
{



private
int
x,
y,
w,
h;

 Será que faz


public
Rectangle(int
nx,
int
ny,
int
nw,
int
nh)
{
 sentido que
ossua




x
=
nx;
 Rectangle p




y
=
ny;
 um método




w
=
nw;
 setWidth?




h
=
nh;



}



public
int
getWidth()
{
return
w;
}
 Nesse caso, como


public
int
getHeight()
{
return
h;
}
 ficaria a


public
void
setWidth(int
nw)
{
w
=
nw;
}
 implementação de


public
void
setHeight(int
nh)
{
h
=
nh;
}

Square?


public
void
draw(Canvas
canvas,
Paint
paint)
{





canvas.drawRect(x,
y,
x
+
w,
y
+
h,
paint);



}

}

Quadrados
Mutantes

public
class
Square
extends
Rectangle
{



public
Square(int
x,
int
y,
int
side)
{
 •  Ao
lado
temos
uma





super(x,
y,
x,
y);



}

implementação



public
void
setWidth(int
nw)
{

bastante
razoável
de





super.setWidth(nw);
 Square





super.setHeight(nw);



}
 •  Essa
implementação



public
void
setHeight(int
nh)
{
 quebra
PSL





super.setWidth(nh);





super.setHeight(nh);



}
 Como é possível que
}
 o princípio da
substituição seja
quebrado?
Área
=
Base
x
Altura

public void stretch(Rectangle r, int fact) {
int area = r.getWidth() * r.getHeight();
r.setWidth(r.getWidth() * fact);
r.setHeight(r.getHeight() * factor);
assert(area * fact * fact == r.getWidth() * r.getHeight());
}

Vocês já o a c ima E com quadrad


Aa ss e r ç ã os,
programaram como é o
com asserções? dispara com comportamento

retângulos? asserção acima
da
?
Porque
deveríamos usar
asserções
prodigamente?
Qual
o
Problema?

•  Herança
designa
uma
relação
“é
um”.

–  Um
quadrado
“é
um”
retângulo.

•  Mas
um
Square,
comportamentalmente
não

é
um
Rectangle!

–  Por
que?
 Nós vimos um
problema
semelhante em
nossa primeira
aula. Você lemb
ra?
Pontos,
e
Conjuntos
de
Pontos

public
class
Dots
{
 public
final
class
Dot
implements
Shape
{



private
final
LinkedList<Dot>
dots
=
new
LinkedList<Dot>();



private
final
float
x,
y;



private
final
List<Dot>
safeDots
=
CollecGons.unmodifiableList(dots);



private
final
int
color,
diameter;



public
Dot
getLastDot()
{
 

public
Dot(float
x,
float
y,
int
color,
int
diameter)
{





return
(dots.size()
<=
0)
?
null
:
dots.getLast();





this.x
=
x;



}
 



this.y
=
y;



public
List<Dot>
getDots()
{
 



this.color
=
color;





return
safeDots;
 



this.diameter
=
diameter;



}
 

}



public
void
addDot(float
x,
float
y,
int
color,
int
diameter)
{



public
float
getX()
{
return
x;
}





dots.add(new
Dot(x,
y,
color,
diameter));



public
float
getY()
{
return
y;
}



}
 

public
int
getColor()
{
return
color;
}



public
void
clearDots()
{
 

public
int
getDiameter()
{
return
diameter;
}





dots.clear();
 

public
void
draw(Canvas
canvas,
Paint
paint)
{



}
 



paint.setStyle(Style.FILL);

}
 



paint.setColor(getColor());





canvas.drawCircle(getX(),
getY(),
getDiameter(),
paint);



}

}

Pontos,
e
Conjuntos
de
Pontos

public
class
Dots
{
 public
final
class
Dot
implements
Shape
{



private
final
LinkedList<Dot>
dots
=
new
LinkedList<Dot>();



private
final
float
x,
y;



private
final
List<Dot>
safeDots
=
Collec6ons.unmodifiableList(dots);



private
final
int
color,
diameter;



public
Dot
getLastDot()
{
 

public
Dot(float
x,
float
y,
int
color,
int
diameter)
{





return
(dots.size()
<=
0)
?
null
:
dots.getLast();





this.x
=
x;



}
 



this.y
=
y;



public
List<Dot>
getDots()
{
 



this.color
=
color;

Alg




return
safeDots;
 



this.diameter
=
diameter;
 uém consegue


}
 

}

ver a catástrofe


public
void
addDot(float
x,
float
y,
int
color,
int
diameter)
{
 iminente?


public
float
getX()
{
return
x;
}





dots.add(new
Dot(x,
y,
color,
diameter));



public
float
getY()
{
return
y;
}



}
 

public
int
getColor()
{
return
color;
}



public
void
clearDots()
{
 

public
int
getDiameter()
{
return
diameter;
}





dots.clear();
 

public
void
draw(Canvas
canvas,
Paint
paint)
{



}
 



paint.setStyle(Style.FILL);

}
 



paint.setColor(getColor());





canvas.drawCircle(getX(),
getY(),
getDiameter(),
paint);



}

}

Coleções
são
coleções

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeWindow window = new ShapeWindow(this, 180, 200);
Dots dots = new Dots();
dots.addDot(12.0F, 13.0F, Color.BLACK, 6);
dots.addDot(22.0F, 43.0F, Color.CYAN, 6);
for (Dot dot : dots.getDots()) {
window.addShape(dot);
}
((LinearLayout)findViewById(R.id.root)).addView(window, 0);
shapeWindow.invalidate();
}
Não
são?

List<Dot> dotCollection = dots.getDots();
dotCollection.add(new Dot(40.0F, 12.0F, Color.BLACK, 6));
O
que
aconteceu:

Muito
embora
CollecGons.unmodifiableList(dots)

• List<Dot> dotCollection = dots.getDots();
retorne
uma
lista
de
pontos,
essa
lista
não

dotCollection.add(new Dot(40.0F, 12.0F, Color.BLACK, 6));
respeita
o
contrato
de
todas
as
listas.

–  Ela
é
mais
restrita.


•  CollecGons.unmodifiableList
não
suporta
a

operação
add.
Ainda
que
sua
interface
contenha

tal
operação.


•  CollecGons.unmodifiableList(dots)
não
respeita
o

Princípio
da
SubsGtuição
de
Liskov!

A
SanGdade
dos
Contratos

•  Se
uma
classe
S
estende
outra
Class
T,
então
S

deve
respeitar
o
contrato
de
T.

–  Toda
invariante
de
T
deve
ser
válida
em
S.


•  Dica:
objetos
mutáveis
têm
mais
chances
de

sofrer
quebras
de
contrato.


O que são objetos


mutáveis?
Princípio
da
Abertura‐Fechamento

•  SoVware
deve
ser
fechado
para
o
uso,
e

aberto
para
a
extensão.


•  Um
programa
é
uma
enGdade
orgânica,
que

cresce
e
se
modifica.

–  Não
dá
para
esperar
o
soVware
alcançar
sua

úlGma
evolução
para
começar
a
usá‐lo.

Como é um
O que causa programa que
mudanças em lida com
programas? mudanças?
Transladando
Formas

Em que situações
Escreva um pequeno programa que
translade por um certo fator (H, V) esse problema
cada forma na lista de formas. ocorre?

Como
implementar
uma solução?
Uma
Solução


public
List<Shape>
moveByFactor(int
h,
int
v,
List<Shape>
shapes)
{





List<Shape>
newShapes
=
new
LinkedList<Shape>();





for
(Shape
shape
:
shapes)
{







if
(shape
instanceof
Rectangle)
{









Rectangle
r
=
(Rectangle)
shape;









newShapes.add(new
Rectangle(r.getX()
+
h,
r.getY()
+
v,
r.getWidth(),
r













.getHeight()));







}
else
if
(shape
instanceof
Square)
{









Square
s
=
(Square)
shape;









newShapes.add(new
Square(s.getX()
+
h,
s.getY()
+
v,
s.getWidth()));







}
else
if
(shape
instanceof
Dot)
{









Dot
d
=
(Dot)
shape;









newShapes.add(new
Dot(d.getX()
+
h,
d.getY()
+
v,
d.getColor(),
d













.getDiameter()));







}
else
{









throw
new
RunGmeExcepGon("Forma
desconhecida!");







}





}





return
newShapes;



}
 DrawShapesAcGvity.java

Usando
a
primeira
solução


public
List<Shape>
moveByFactor(int
h,
int
v,
List<Shape>
shapes)
{

@Override





List<Shape>
newShapes
=
new
LinkedList<Shape>();

public
void
onCreate(Bundle
savedInstanceState)
{






for
(Shape
shape
:
shapes)
{



super.onCreate(savedInstanceState);







if
(shape
instanceof
Rectangle)
{



setContentView(R.layout.main);









Rectangle
r
=
(Rectangle)
shape;



List<Shape>
shapes
=
new
LinkedList<Shape>();









newShapes.add(new
Rectangle(r.getX()
+
h,
r.getY()
+
v,
r.getWidth(),
r



shapes.add(new
Rectangle(0,
0,
10,
18));













.getHeight()));



shapes.add(new
Square(90,
90,
25));







}
else
if
(shape
instanceof
Square)
{



shapes.add(new
Dot(12.0F,
13.0F,
Color.BLACK,
6));









Square
s
=
(Square)
shape;



shapes.add(new
Dot(22.0F,
43.0F,
Color.CYAN,
6));









newShapes.add(new
Square(s.getX()
+
h,
s.getY()
+
v,
s.getWidth()));



shapes.add(new
Dot(8.0F,
33.0F,
Color.GREEN,
6));







}
else
if
(shape
instanceof
Dot)
{



ShapeWindow
shapeWindow
=
new
ShapeWindow(this,
180,
200);









Dot
d
=
(Dot)
shape;



for
(Shape
shape
:
moveByFactor(50,
50,
shapes))
{










newShapes.add(new
Dot(d.getX()
+
h,
d.getY()
+
v,
d.getColor(),
d





shapeWindow.addShape(shape);













.getDiameter()));







}
else
{
 

}




((LinearLayout)
findViewById(R.id.root)).addView(shapeWindow,
0);









throw
new
RunGmeExcepGon("Forma
desconhecida!");







}
 

shapeWindow.invalidate();





}
 }





return
newShapes;



}

Esse programa

DrawShapesAcGvity.java
 Análise
 teria de ser


modificado se

public
List<Shape>
moveByFactor(int
h,
int
v,
List<Shape>
shapes)
{
 houvesse u
@Override
 ma




List<Shape>
newShapes
=
new
LinkedList<Shape>();
 nova forma?
public
void
onCreate(Bundle
savedInstanceState)
{






for
(Shape
shape
:
shapes)
{



super.onCreate(savedInstanceState);







if
(shape
instanceof
Rectangle)
{



setContentView(R.layout.main);









Rectangle
r
=
(Rectangle)
shape;



List<Shape>
shapes
=
new
LinkedList<Shape>();









newShapes.add(new
Rectangle(r.getX()
+
h,
r.getY()
+
v,
r.getWidth(),
r



shapes.add(new
Rectangle(0,
0,
10,
18));













.getHeight()));



shapes.add(new
Square(90,
90,
25));







}
else
if
(shape
instanceof
Square)
{



shapes.add(new
Dot(12.0F,
13.0F,
Color.BLACK,
6));









Square
s
=
(Square)
shape;



shapes.add(new
Dot(22.0F,
43.0F,
Color.CYAN,
6));









newShapes.add(new
Square(s.getX()
+
h,
s.getY()
+
v,
s.getWidth()));



shapes.add(new
Dot(8.0F,
33.0F,
Color.GREEN,
6));







}
else
if
(shape
instanceof
Dot)
{



ShapeWindow
shapeWindow
=
new
ShapeWindow(this,
180,
200);









Dot
d
=
(Dot)
shape;



for
(Shape
shape
:
moveByFactor(50,
50,
shapes))
{










newShapes.add(new
Dot(d.getX()
+
h,
d.getY()
+
v,
d.getColor(),
d





shapeWindow.addShape(shape);













.getDiameter()));







}
else
{
 

}

 Será que é


((LinearLayout)
findViewById(R.id.root)).addView(shapeWindow,
0);









throw
new
RunGmeExcepGon("Forma
desconhecida!");
 possível fazer um






}
 

shapeWindow.invalidate();

programa que




}
 }

não precise ser




return
newShapes;



}
 modificado?
OO
em
Ação

•  Se
as
formas
“soubessem”
se
transladar,
então

não
seria
necessário
implementar
essa
ação

externamente.

•  Na
verdade,
a
úlGma
solução
não
é
nem
um

pouco
orientada
a
objetos.

–  Ela
é
orientada
às
operações.

–  A
forma,
nesse
caso,
não
sabe
executar
a
ação

esperada.


Por que?
Movendo
Responsabilidades

•  Podemos
dar
para
cada
forma
a
inteligência

para
transladar‐se.

–  Como
a
forma
faz
isso
não
"é
da
nossa
conta".


public
interface
Shape
{
 public
final
class
Dot
implements
Shape
{



void
draw(Canvas
canvas,
Paint
paint);
 

public
void
transpose(int
newX,
int
newY)
{



void
transpose(int
x,
int
y);
 



this.x
=
newX;

}
 



this.y
=
newY;



}

public
class
Rectangle
implements
Shape
{

}



private
int
x,
y,
w,
h;
 Como ficaria o


public
void
transpose(int
newX,
int
newY)
{

método




this.x
=
newX;





this.y
=
newY;
 moveByFactor


}
 agora?
}

Interface
mais
genérica

public
List<Shape>
newMoveByFactor(int
h,
int
v,
List<Shape>
shapes)
{



for
(Shape
shape
:
shapes)
{





shape.transpose(h,
v);
 Como esse método


}
 deveria ser


return
shapes;
 modificado, se for
}
 criada uma forma
nova?

•  Uma
vez
que
a
forma
"sabe"
se
transpor,

podemos
pedir‐lhe
que
execute
essa
tarefa

sem
precisar
conhecer
o
"como"
a
tarefa
é

realizada.

–  Isso
é
Programação
Orientada
a
Objetos

Programação
Orientada
a
Objetos

public
List<Shape>
newMoveByFactor(int
h,
int
v,
List<Shape>
shapes)
{



for
(Shape
shape
:
shapes)
{





shape.transpose(h,
v);

Mas, o quê é


}
 programação


return
shapes;
 orientada a
}
 objetos?

•  Uma
vez
que
a
forma
"sabe"
se
transpor,

podemos
pedir‐lhe
que
execute
essa
tarefa

sem
precisar
conhecer
o
"como"
a
tarefa
é

realizada.

–  Isso
é
Programação
Orientada
a
Objetos

Antropomorfização
dos
Dados

•  O
Cerne
da
POO
é
a
"antropomorfização"
dos

dados.

–  Dados
são
"inteligentes".

–  Dados
"sabem"
fazer
as
coisas.

–  A
lista
"sabe"
dizer
quantos
elementos
ela

contêm,
e
o
ponto
sabe
dizer
quais
são
suas

coordenadas
X
e
Y,
por
exemplo.

Por que essa
"inteligência" é
tão importante
?
Inteligência
Leva
ao
Encapsulamento

•  Se
o
Gpo
"sabe"
realizar
uma
ação,
o
"como"

tal
ação
é
realizada
passa
a
não
ser
relevante.

•  Torna‐se
possível,
assim,
que
o
"como",
isto
é,

a
implementação,
seja
encapsulada.

•  Encapsulação
foi
uma
idéia
esperta
Nível
10

em
ciência
da
computação.

•  Antropomorfização
foi
uma
idéia
esperta
Nível

9
em
ciência
da
computação.
 Que outras
idéias espertas
?
em CC existem
Encapsulamento

•  Se
o
Gpo
"sabe"
realizar
uma
ação,
o
"como"

tal
ação
é
realizada
passa
a
não
ser
relevante.

Por
que
encapsulamento

•  Torna‐se
possível,
assim,
que
o
"como",
isto
é,

a
implementação,
seja
encapsulada.

é
tão
importante?

•  Encapsulação
foi
uma
idéia
esperta
Nível
10

em
ciência
da
computação.

•  Antropomorfização
foi
uma
idéia
esperta
Nível

9
em
ciência
da
computação.

O
Porquê
do
Encapsulamento

•  Encapsulamento
existe
para
reduzir
o
custo
de

modificar
um
programa.


Por que
Por que o
programas têm Qual o custo de o
encapsulament
de ser modificar um
diminui esse
modificados? programa?
custo?
Estudo
de
caso:
strings
em
C

#include
<stdio.h>

O que faz o
int
main(int
argc,
char**
argv)
{
 programa ao


int
i
=
1;
 lado?


for
(;
i
<
argc;
i++)
{





int
j
=
0;





for
(;
argv[i][j]
!=
'\0';
j++)
;





prinˆ("Size
of
%s
=
%d\n",
argv[i],
j);



}

}

Estudo
de
caso:
strings
em
C

#include
<stdio.h>

int
main(int
argc,
char**
argv)
{

Compare essas duas


int
i
=
1;
 implementações do


for
(;
i
<
argc;
i++)
{
 mesmo programa.




int
j
=
0;
 Qual a vantagem de




for
(;
argv[i][j]
!=
'\0';
j++)
;
 uma com relação à




prinˆ("Size
of
%s
=
%d\n",
argv[i],
j);
 outra?


}

}

#include
<stdio.h>

#include
<string.h>

int
main(int
argc,
char**
argv)
{



int
i
=
1;



for
(;
i
<
argc;
i++)
{





prinˆ("Size
of
%s
=
%d\n",
argv[i],
strlen(argv[i]));



}

}

Estudo
de
caso:
strings
em
C

#include
<stdio.h>

int
main(int
argc,
char**
argv)
{

A implementação ao lado


int
i
=
1;
 depende de um detalhe da


for
(;
i
<
argc;
i++)
{
 implementação de strings em C.




int
j
=
0;
 Se o comitê da linguagem decidir




for
(;
argv[i][j]
!=
'\0';
j++)
;
 mudar esse detalhe, esse




prinˆ("Size
of
%s
=
%d\n",
argv[i],
j);
 programa deixa de funcionar.


}

}

#include
<stdio.h>

#include
<string.h>

int
main(int
argc,
char**
argv)
{



int
i
=
1;



for
(;
i
<
argc;
i++)
{





prinˆ("Size
of
%s
=
%d\n",
argv[i],
strlen(argv[i]));



}

}

Estudo
de
caso:
strings
em
C

#include
<stdio.h>
 O programa abaixo não depende
int
main(int
argc,
char**
argv)
{
 desse detalhe de implementação.


int
i
=
1;

Ele utiliza uma interface. Se a


for
(;
i
<
argc;
i++)
{

implementação de strings mudar, o




int
j
=
0;





for
(;
argv[i][j]
!=
'\0';
j++)
;
 programa abaixo não precisa ser




prinˆ("Size
of
%s
=
%d\n",
argv[i],
j);
 modificado, desde que a


}
 implementação da interface se
}
 adeque à nova realidade.
#include
<stdio.h>

#include
<string.h>

int
main(int
argc,
char**
argv)
{



int
i
=
1;



for
(;
i
<
argc;
i++)
{





prinˆ("Size
of
%s
=
%d\n",
argv[i],
strlen(argv[i]));



}

}

Estudo
de
caso:
strings
em
C

#include
<stdio.h>

A linguagem C não possui
int
main(int
argc,
char**
argv)
{

nenhum mecanismo que force o


int
i
=
1;



for
(;
i
<
argc;
i++)
{
 programador a não utilizar




int
j
=
0;
 detalhes de implementação.




for
(;
argv[i][j]
!=
'\0';
j++)
;
 Encapsulação se dá via




prinˆ("Size
of
%s
=
%d\n",
argv[i],
j);
 disciplina de programação.


}

}

#include
<stdio.h>

Linguagens mais #include
<string.h>

modernas disponibilizam int
main(int
argc,
char**
argv)
{

recursos sintáticos para 

int
i
=
1;

encapsular dados. 

for
(;
i
<
argc;
i++)
{





prinˆ("Size
of
%s
=
%d\n",
argv[i],
strlen(argv[i]));

Quais recursos


}

java provê?
}

Encapsulamento
Sempre?

•  Propriedades
de
objetos
imutáveis
não

precisam
ser
necessariamente
encapsuladas.

public
class
ImmutableCircle
implements
Shape
{

O que é um 

public
final
int
x,
y,
r;


objeto 

public
Circle(int
x,
int
y,
int
r)
{

imutável? 



this.x
=
x;





this.y
=
y;

Quais as 



this.r
=
r;

vantagens 

}

de objetos 

public
void
draw(Canvas
canvas,
Paint
paint)
{

imutáveis? Por que não é 



canvas.drawCircle(x,
y,
r,
paint);

necessário 

}

encapsular 

public
void
transpose(int
x,
int
y)
{

propriedades 



throw
new
RunGmeExcepGon("Circle
is
imutable!");

imutáveis? 

}

}

Sempre
a
Balança

•  Propriedades
de
objetos
imutáveis
não

precisam
ser
necessariamente
encapsuladas.

public
class
ImmutableCircle
implements
Shape
{

O que é um 

public
final
int
x,
y,
r;


objeto 

public
Circle(int
x,
int
y,
int
r)
{

imutável? 



this.x
=
x;

Que 



this.y
=
y;

Quais as princípio 



this.r
=
r;

esta
vantagensmos 

}

ferindo aqu
de objetos i? 

public
void
draw(Canvas
canvas,
Paint
paint)
{

imutáveis? Por que não é 



canvas.drawCircle(x,
y,
r,
paint);

necessário 

}

Como encapsular 

public
void
transpose(int
x,
int
y)
{

poderíamos propriedades 



throw
new
Run6meExcep6on("Circle
is
imutable!");

resolver isso?
imutáveis? 

}

}

Inspeção
de
Tipos
Dinâmica


public
List<Shape>
moveByFactor(int
h,
int
v,
List<Shape>
shapes)
{





List<Shape>
newShapes
=
new
LinkedList<Shape>();
 Inspeção de




for
(Shape
shape
:
shapes)
{
 tipos é um






if
(shape
instanceof
Rectangle)
{
 sintoma de








Rectangle
r
=
(Rectangle)
shape;
 que o código








newShapes.add(new
Rectangle(r.getX()
+
h,
r.getY()
+
v,
r.getWidth(),
r
 não adere ao












.getHeight()));
 princípio da






}
else
if
(shape
instanceof
Square)
{
 abertura-








Square
s
=
(Square)
shape;
 fechamento.








newShapes.add(new
Square(s.getX()
+
h,
s.getY()
+
v,
s.getWidth()));







}
else
if
(shape
instanceof
Dot)
{









Dot
d
=
(Dot)
shape;
 Mas há








newShapes.add(new
Dot(d.getX()
+
h,
d.getY()
+
v,
d.getColor(),
d
 situações em












.getDiameter()));
 que o uso






}
else
{
 dessa forma








throw
new
RunGmeExcepGon("Forma
desconhecida!");
 de reflexão é






}
 positivo.




}
 Quais?




return
newShapes;



}

Inspeção
Dinâmica
do
Bem


public
List<ImutableCircle>
getImutableCircles(List<Shape>
shapes)
{





List<ImutableCircle>
circles
=
new
LinkedList<ImutableCircle>();





for
(Shape
shape
:
shapes)
{







if
(shape
instanceof
ImutableCircle)
{









circles.add((ImutableCircle)shape);







}





}





return
circles;
 Por que nesse Ainda assim


}
 caso a inspeçã esse código não
o
dinâmica é é de todo
benéfica? agradável.
O
Segredo
da
Abetura‐Fechamento


A
chave
para
desenvolvermos
soVware

extensível
é
programarmos
para
as

interfaces
mais
genéricas.


s mais
Por que interface
o
genéricas tornam
f t wa r e m a is s im ples
so
de estender?
Interfaces
Genéricas

public
List<Shape>
moveByFactor(int
h,
int
v,
List<Shape>
shapes)
{



for
(Shape
shape
:
shapes)
{
 Shape





shape.transpose(h,
v);



}



return
shapes;

}
 Rectangle
 Ellipses

e
Porque a interfac

acima é preferíve

interface abaixo? Square
 Trapezoid
 Dot
 Circle


public
List<Rectangle>
moveByFactor(int
h,
int
v,
List<Rectangle>
shapes)
{



for
(Rectangle
shape
:
shapes)
{





shape.transpose(h,
v);



}



return
shapes;

}

Recapitulando

•  Princípio
da
SubsGtuição
de
Liskov:
código
que

espera
um
Gpo
T
deve
poder
receber
um
Gpo

S
que
seja
subGpo
de
T.

•  Princípio
da
Abertura‐Fechamento:
código

deve
ser
fechado
para
uso,
e
aberto
para

extensões.


You might also like