Anda di halaman 1dari 19

Desarrollo de Software

Para disear un software el proceso normal a seguir es el siguiente:


1. Anlisis:
Se destacan las siguientes actividades:
Detectar el contexto en el que est ocurriendo el problema.
Detectar los requerimientos funcionales. Es decir, refiere con lo
que el cliente impone, es decir las restricciones.
2. Diseo:
Identificar qu caractersticas tendr la solucin representada a
travs de diagramas, dibujos, texto, etc.
3. Implementacin:
NOTAS:
Las primeras etapas son crticas ya que mientras ms tarde se
detecta un error, ms costoso es corregirlo.
Es imposible resolver un problema que no se entiende. Esto es en
la etapa del anlisis.
A veces para identificar entidades, ver si podemos encontrar
sustantivos del enunciado del problema.
Al agregar atributos ver si realmente estos tienen que ver con los
requerimientos funcionales.

1.

UML (Unified Modeling Languaje)

1.1

Tipos de diagramas que soporta UML

Diagrama de clase:
Representa la estructura esttica de las clases, interfaces y
relaciones en un modelo de objeto
Diagrama de casos de uso:
Representan las funciones de un sistema desde una perspectiva de
usuarios.
Diagrama de objetos:
Ilustran objetos y enlaces.

Diagrama de colaboracin:
Ilustran interacciones (en otras palabras, mensajes) entre objetos
usando una representacin espacial.
Diagramas de secuencia:
Enfocado en la cronologa de las interacciones entre objetos.
Diagrama de transicin de estado:
Expresan los comportamientos de una clase en trminos del estado
de los objetos.
Diagrama de actividad:
Especifican el comportamiento de una operacin (un mtodo) como
un conjunto de acciones.
Diagrama de componentes:
Muestran los componentes fsicos de un sistema de software.
Diagrama de despliegue:
Muestran los despliegues fsicos de componentes en piezas
determinadas de software.

1.2

Niveles visibles de atributos y mtodos

Pblico: se representa con un +.

Protegido: el elemento es visible para todas las subclases de la


clase. Se representa con un #.
Privado: El elemento es visible solo para la clase. Se representa
con un -.

2.
PROGRAMACIN ORIENTADA A
OBJETOS
2.1 PILARES
La POO se basa en 4 pilares los cuales detallamos a continuacin.
A. Encapsulacin
Tcnica utilizada para ocultar las propiedades y el comportamiento
de un objeto con el fin de restringir el acceso directo a sus atributos
y al detalle de la implementacin de sus mtodos. Esta restriccin
evita que dicho objeto sea manipulado por operaciones distintas a
las definidas.
Todo esto permite la consistencia en la informacin, el aumento de
la cohesin y que el cliente pueda hacer uso de dicho objeto el cual
le interesar saber las funciones que realiza mas no el cmo est
implementada determinada funcionalidad.
Existen diferentes tipos de restricciones pero tener en cuenta la
siguiente distincin:

La parte pblica: accesible para el resto de las clases. Para ello


se usa la sentencia public.
La parte privada: A ella slo pueden acceder los mtodos de la
clase. Para ello se usa la sentencia private o protected.
La clase principal SIEMPRE tiene que ser pblica, de lo
contrario si la importamos el compilador nos cantar un error.
Todos los atributos (variables) que no necesiten ser vistos por
otras clases se declararn como private o a lo sumo como
protected.

B. Abstraccin
Se refiere al acto de concentrar las caractersticas y
comportamientos necesarios para la correcta representacin del
objeto dentro del sistema.

Como resumen de los conceptos expuestos anteriormente podemos


decir que:
Los objetos son encapsulaciones de abstracciones en la POO.

La unidad de encapsulacin en la POO es el objeto.

C. Polimorfismo
Es la capacidad de tener mtodos con el mismo nombre, con
comportamientos diferentes, conocido como la sobre-escritura de
mtodos y la sobrecarga de operadores.
El trmino polimorfismo significa que hay un nombre (variable,
funcin o clase) y muchos significados diferentes (distintas
definiciones).
Formas de polimorfismo:
Polimorfismo de asignacin (variables polimorfas)

Polimorfismo puro (funcin polimorfa)

Polimorfismo ad hoc (sobrecarga)

Polimorfismo de inclusin (redefinicin)

Polimorfismo paramtrico (genericidad)

Ms informacin
Revisar los videos 9 y 10 de Mdulo 3, Leccin 1 de los videos de
Java y POO de Global Mentoring.
D. Herencia
Refiere al mecanismo de definir una clase a partir de la definicin
de otra ya existente. Con esto se consigue que una clase herede
todos los atributos y mtodos de sus ancestros.
Hay dos tipos de herencia: Herencia Simple y Herencia Mltiple.
Java slo permite herencia simple la cual refiere a que se puede
definir nuevas clases a partir solo de una clase inicial. Es decir no
est permitido que una clase herede de varias clases padre.
Extends es la palabra reservada que se usa para indicar que una
clase hereda de otra clase ya sea normal o abstracta.
Tambin debemos recordar que las 2 razones ms importantes para
el uso de la herencia son:
Reutilizacin de cdigo
Uso del polimorfismo

Una subclase puede invocar a un mtodo de la clase padre por


medio de la palabra "super". Esta palabra reservada tiene
funcionalidad similar al operador this con la diferencia que hace
referencia no a s misma, sino a la clase padre.
El mtodo que se invoca con la palabra super no necesariamente
tendra que estar declarado en la clase padre sino podra estar
declarado en una clase ms arriba en la jerarqua de clases.

2.2 CONCEPTOS FUNDAMENTALES


COHESIN Y ACOPLAMIENTO (COUPLING AND
COHESION)
Estos dos temas, la cohesin y el acoplamiento, tienen que ver con la
calidad de un diseo orientado a objetos. En general un buen diseo
pide un acoplamiento bajo y evita un acoplamiento estrecho y un
buen diseo orientado a objetos pide una alta cohesin y evita la baja
cohesin. Como con la mayora de las discusiones sobre diseo de
orientacin a objetos, las metas de una aplicacin son:
a. Facilidad de creacin.
b. Facilidad de mantenimiento.
c. Facilidad de mejora.
Cohesin
Se refiere al enfoque ms o menos preciso que se le da al
objetivo de una clase. Es por eso que cuando se desarrolla
software, se habla de alta cohesin que es la forma ms precisa
posible de establecer el objetivo de una clase, delegando las
tareas complementarias a otros componentes.
Cuanto ms enfoquemos el propsito de la clase, mayor ser su
cohesin. El objetivo es tener una alta cohesin.
Acoplamiento
El acoplamiento entre clases es la medida de interconexin o
dependencia entre esas clases, es decir es la medida con la que
un objeto depende de otro para funcionar, entre menor sea esta
medida, es mejor.

Acoplamiento fuerte significa que las clases relacionadas


necesitan saber detalles internos unas de otras, los cambios se
propagan por el sistema y el sistema es posiblemente ms difcil
de entender. El objetivo es tener un bajo acoplamiento y esto se
consigue al programar contra interfaces mas no contra clases
concretas.
El acoplamiento es un mal necesario ya que sin l los objetos no
podran interactuar para resolver problemas, pero cuan menor
sea el acoplamiento es ms reutilizable, comprobable y flexible.
Ejemplo:
Si yo tengo que hacer uso de un mtodo en la clase Desarmador,
un alto acoplamiento sera:
Desarmador desarmador = new Desarmador();
desarmador.reparar();
En cambio, si deseo tener un bajo acoplamiento lo mejor sera
crear un interfaz IHerramienta y que la clase Desarmador
implemente esta interfaz. Esto con el objetivo que en un futuro
ya no se desee usar un desarmador sino un martillo, no
tengamos que hacer muchos cambios en el cdigo. Ejemplo:
IHerramienta desarmador = new Desarmador();
herramienta.reparar();
IHerramienta martillo = new Martillo();
herramienta.reparar();
Para mayor informacin acceder a:
http://www.javatutoriales.com/2011/11/sun-certified-java-programmer-6-cx310.html

CLASE
Una clase es la definicin de una estructura la cual puede
contener propiedades y mtodos (o llamados tambin atributos y
operaciones respectivamente). Esta estructura definida es la que
tendr posteriormente un objeto creado a partir de esta clase.
Fsicamente una clase es un archivo con nombre y extensin
(.java). Dentro de este archivo podemos implementar: Mtodos
miembros y Datos miembros (atributos) que pueden ser de tipo
primitivos o referencias. Un archivo .java al compilar pasa a tener
una extensin .class.

Una clase es una abstraccin del mundo real.

OBJETO
Un objeto es la representacin materializada de la clase. Esta
materializacin se almacena en la memoria del ordenador.
La clase es la definicin general y el objeto es la materializacin
concreta de dicha definicin general.
Ejemplo:
La clase vendra a ser rbol y una instancia podra ser peral
(rbol que produce peras).
El proceso para crear objetos se llama instanciacin y se usa la
palabra new. Ejemplo:
Punto p;
p = new Punto( );
En la primera lnea del ejemplo se declara una variable (p) que es
de tipo Punto. La variable no contiene ningn valor.
En la segunda lnea se crea un objeto de tipo Punto y se devuelve
su referencia (del objeto) la cual es almacenada en la variable p.
Es decir p est almacenando la direccin de memoria del objeto
recin creado.
Es decir, el operador new hace lo siguiente:
1. Reserva espacio en memoria para crear un objeto nuevo.
2. Instancia una clase creando el objeto en la posicin de
memoria que reserv.
3. Devuelve la referencia que apunta al objeto creado.
Esa referencia es la direccin del espacio en memoria que
ocupa el objeto recin creado.
4. Finalmente esa referencia devuelta puede ser almacenada
en una variable.
Utilizar dos veces el operador new con la misma referencia o el
mismo nombre declarado, provoca que haya valores u objetos
que se quedan sin referencia. A eso se le suele llamar basura
digital y por tanto el recolector los elimina.

Figura 2.1: Lo que sucede en la memoria al aplicar el operador


new.

CONSTRUCTOR

Son mtodos especiales proporcionados por cada clase. Estos


mtodos son responsables de inicializar con determinados
valores a los datos miembros del objeto.
Tienen el mismo nombre de la clase.
Pueden haber varios constructores en una clase pero siempre
con el mismo nombre pero diferente cantidad y tipo de
argumentos.

RECOLECCIN DE BASURA

Muchos otros lenguajes orientados a objetos necesitan que se siga la


pista de los objetos que se han creado y luego se destruyan cuando
no se necesiten. Escribir cdigo para manejar la memoria de esta es
forma es aburrido y propenso a errores.
Java permite ahorrarse esto, permitiendo crear tantos objetos como
se quiera pero nunca tienen que ser destruidos. El entorno de
ejecucin Java borra los objetos cuando determina que no se van a
utilizar ms. Este proceso es conocido como recoleccin de basura.
Se escoge un objeto para la recoleccin de basura cuando no existen
ms referencias a ese objeto.
Recolector de Basura

El entorno de ejecucin de Java tiene un recolector de basura que


peridicamente libera la memoria ocupada por los objetos que no
se van a necesitar ms.
Finalizacin
Antes de que un objeto sea recolectado, el recolector de basura le
da una oportunidad para limpiarse l mismo mediante la llamada
al mtodo finalize() del propio objeto. Este proceso es conocido
como finalizacin.
El mtodo finalize() es un miembro de la clase java.lang.Object.
Una clase debe sobrescribir el mtodo finalize() para realizar
cualquier finalizacin necesaria para los objetos de ese tipo.

CLASE ABSTRACTA
Una clase abstracta es la definicin de conductas "genricas", es
decir las superclases abstractas definen y pueden implementar
parcialmente la conducta pero gran parte de la clase no est definida
ni implementada.
Recin se concluirn los detalles con subclases especializadas o
clases hijas y recin aqu se terminar o agregar la funcionalidad a
los mtodos abstractos declarados en la superclase abstracta.
Una clase abstracta no se puede instanciar, es decir, no se pueden
crear objetos de una clase abstracta. El objetivo de las clases
abstractas es aplicar herencia lo que finalmente permite la
reutilizacin de cdigo.
Para ms detalle tener en cuenta la siguiente nota:
Hay ocasiones, cuando se desarrolla una jerarqua de clases en
que algn comportamiento est presente en todas ellas pero se
materializa de forma distinta para cada una. Por ejemplo,
pensemos en una estructura de clases para manipular figuras
geomtricas. Podramos pensar en tener una clase genrica, que
podra llamarse FiguraGeometrica y una serie de clases que
extienden a la anterior que podran ser Crculo, Polgono, etc.
Podra haber un mtodo dibujar dado que sobre todas las figuras
puede llevarse a cabo esta accin, pero las operaciones
concretas para llevarla a cabo dependen del tipo de figura en
concreto (de su clase). Por otra parte la accin dibujar no tiene
sentido para la clase genrica FiguraGeometrica, porque esta
clase representa una abstraccin del conjunto de figuras
posibles.
Para resolver esta problemtica Java proporciona las clases y
mtodos abstractos. Un mtodo abstracto es un mtodo
declarado en una clase para el cual esa clase no proporciona la

implementacin (el cdigo). Una clase abstracta es una clase que


tiene al menos un mtodo abstracto. Una clase que extiende a
una clase abstracta debe implementar los mtodos abstractos
(escribir el cdigo) o bien volverlos a declarar como abstractos,
con lo que ella misma se convierte tambin en clase abstracta.

INTERFACES
Las interfaces son un tipo de clase especial es decir una interfaz es
una clase puramente abstracta.
En una interfaz se indican y definen variables y mtodos pero estos
no se implementan es decir se indica el que pero no el cmo, sus
mtodos estn vacos no hacen nada. Esto es con el objetivo de
obligar a otros a implementar los mtodos de la interface pero
sujetndose a cumplir con sus cada una de sus firmas. Con esto se
establece un protocolo entre clases.
Si esta interfaz contiene datos miembros, estos son siempre static
final porque una interfaz nunca puede ser instanciada (no tiene
constructor), de tal modo para acceder a alguno de sus datos
miembros basta con colocar el nombre de la interfaz seguido del
punto y el nombre del dato miembro (o el atributo). Si en sus datos
miembros no se especifica static final, por defecto el compilador
asume que as son.
Para indicar que una clase implementa una o ms interfaces, se usa
la palabra implements y ya con eso el compilador se encarga de
verificar que la clase actual declare e implemente todos los mtodos
declarados en la interfaz.
Con el uso de interfaces se puede "simular" la herencia mltiple que
Java no soporta.
La notacin que indica que se trata de una interfaz es la siguiente:
<< interface >>
A continuacin tenemos una clase simpleClass heredando de una
sencilla interfaz llamada simpleInterface.

Cuando vemos un diagrama de clase Java que contiene la etiqueta


<<interface>>, deberamos esperar que hubiese cualquier
implementacin de los mtodos que declara. Como se ve el resto del
diagrama es prcticamente igual que un diagrama de clases.
Tambin tenemos que tener presente en este diagrama la notacin de
herencia, que es une flecha que va de una clase (simpleClass) a la
clase de la que hereda (simpleInterface).
En java hay dos tipos de herencia: extensin e implementacin.
Como el diagrama muestra una clase heredando de una interfaz
tenemos una lnea discontinua representando una implementacin.
El siguiente diagrama muestra una lnea de extensin:

Observar que la lnea que va de otherClass a simpleClass es una


lnea continua: esta es la representacin UML para una clase
extendiendo de otra.
Por lo tanto, recordar que una interfaz nunca se puede instanciar, tan
solo se implementa.
Cuando uno implementa una interfaz sucede dos cosas:
1. Si o si se tiene que implementar todos sus mtodos.
2. Si no se desea implementar todos sus mtodos, debe declarar
esa clase como abstracta
Ejemplo del uso de interfaces:
Declarar una interface alimentos y sus mtodos: getCalorias() y
comer(). Luego para implementar esta interfaz definimos las
clases Postre, Frutas Bocadillo en donde ah recin implemento
los dos mtodos: getCalorias() y come().
Para ms informacin sobre clases abstractas, interfaces acceder
a las paginas pag. 184 sobre clases abstractas, pag. 190 sobre
interfaces, pag. 192 sobre diferencias entre Interfaz y clase
abstracta del libro Desarrollo web con JSP.
Programacin orientada a interfaces
Es una programacin basada en la creacin de una interface a la
cual se le generan n implementaciones para as disminuir el
cdigo intrusivo en nuestro sistema, creando atributos de tipo
interface en lugar de clases concretas.
Adems, la programacin orientada a interfaces significa que
podemos cambiar la implementacin de una clase de manera
programtica o declarativa en tiempo de ejecucin.
Ejemplo:
public class Trabajador
{
private int codigo;
private Martillo martillo;
public int getCodigo() { return codigo; }
public void setCodigo(int codigo)
{ this.codigo = codigo; }
public Martillo getMartillo() { return martillo; }

public void setMartillo(Martillo martillo)


{ this.martillo = martillo; }
}
public class Martillo
{
...
}
Si ms adelante deseamos que nuestra clase Trabajador ya no
use un martillo sino desarmador, tendramos que cambiar los
constructores, setters y getters del atributo martillo. Por lo tanto
se genera muchos cambios y problemas.
Cuando decimos programacin orientada a interfaces nos
referimos a que lo ms apropiado es indicar interfaces en vez de
clases concretas como tipos de atributo.
En este caso tendremos dos clases concretas: Martillo y
Desarmador y ambas clases implementan una interface
Herramienta. Por lo tanto a nuestra clase Trabajador no le
importa que herramienta use y con esto logramos que ms
adelante el decida que herramienta usar. En trminos de
programacin estamos dejando de ser tan intrusivos en la clase
Trabajador, ya que l puede implementar su Herramienta sin
alterar el cdigo de la clase Trabajador.
Finalmente el tipo Herramienta se colocara como tipo del
atributo en la clase Trabajador de la siguiente manera:
public class Trabajador
{
private int codigo;
private Herramienta herramienta;
public int getCodigo()
{ return codigo; }
public void setCodigo(int codigo)
{ this.codigo = codigo; }
public Herramienta getHerramienta()
{ return herramienta; }
public void setHerramienta(Herramienta herramienta)
{ this.herramienta = herramienta; }
}

public class Martillo implements Herramienta


{ ... }
public class Desarmador implements Herramienta
{ ... }
Eleccin entre interfaces y clases abstractas
Como norma general, elegir una clase abstracta cuando haya
sentido proporcionar una cierta medida de funcionalidad
predefinida y las subclases vayan a funcionar slo como una
versin extendida de sus superclases.
Por el contrario, cuando no haya sentido proporcionar detalles de
implementacin de una superclase, o las subclases puedan
necesitar funcionar como objetos radicalmente diferentes, usar
una interfaz.

EN RESMEN
Visto los conceptos de interfaces, clases abstractas y clases
concretas, vemos que tenemos 3 niveles de abstraccin:
1. Primero las interfaces --> 100% abstractas
2. Segundo las clases abstractas --> no se sabe, depende como lo
decida el programador.
3. Tercero las clases concretas --> 100 % concretas.
Mayor informacin:
http://codejavu.blogspot.com/2013/05/interfaces-en-java.html

2.3 PROGRAMACIN
La experiencia demuestra que la mejor manera de desarrollar y
mantener un programa extenso es construirlo a partir de pequeas
piezas es decir aplicar el concepto de divide y vencers.

MODIFICADORES DE ACCESO
a. public
b. private
Es el nivel de acceso ms restringido.
Solo lo pueden ver elementos de la misma clase.
c. protected
Permite a la propia clase y las subclases que accedan a los
miembros. Es decir slo tendrn acceso aquellos que se
encuentren en su rbol de herencia.
d. Vaco o sin modificador:
O tambin llamado modificador de acceso de paquete. Lo podrn
ver otras clases que se encuentren en el mismo paquete.
Ms informacin: http://soft-mas.com/encapsulamiento-en-java/

TRABAJANDO CON MTODOS


Cada mtodo que implementemos debe de realizar una tarea bien
definida. El nombre de ese mtodo debe de expresar esa tarea con
efectividad. Si no podemos elegir un nombre conciso que exprese la
tarea de un mtodo tal vez estamos tratando de realizar diversas
tareas en un mismo mtodo.

MTODOS, PROCEDIMIENTOS, RETURN


Cuando se llama a un procedimiento o a un mtodo, al encontrarse
con una sentencia return se pasa el valor especificado al cdigo que
llam a dicho mtodo y se devuelve el control al cdigo invocador. Su

misin tiene que ver con el control de flujo: se deja de ejecutar cdigo
secuencialmente y se pasa al cdigo que invoc al mtodo. Esta
sentencia tambin est profundamente relacionada con los mtodos,
ya que es la sentencia que le permite devolver al mtodo un valor.

PALABRA static
a. Variables static
Ver ejemplo:

Una variable static es una variable que pertenece a una clase mas
no a una instancia de dicha clase, es decir no hay una copia para
cada objeto creado sino que hay una sola copia que es compartida
por todos los objetos creados de esa clase.
Cuando se crean objetos de una clase que contiene campos o
atributos static, todos los objetos de esa clase comparten una copia
de los atributos static de esa clase. Por lo tanto cuando el objeto
mediante un mtodo set modifica dicho campo static, cambia el
valor para todos las instancias de esa clase.

Las variables estticas de una clase existen, se inicializan y pueden


usarse antes de que se cree algn objeto de la clase.
Un ejemplo adicional para clarificar ms este tema en la pag. 346
del libro Java, Como programar, 7ma ed.
En resmen:
Variables de clase = variables static = variable miembro =
miembros de clase static.
Estas variables se caracterizan por ser propias de la clase ms
no del objeto.
Variables de instancia = variables normales

b. Mtodos static
Algunas veces un mtodo realiza una tarea que no depende del
contenido de ningn objeto. Estos mtodos son llamados mtodos
estticos o mtodos de clase. Es decir este tipo de mtodos se
asocian a la clase ms no al objeto.
Dado que los mtodos estticos tienen sentido a nivel de clase ms
no a nivel de objeto, los mtodos estticos no pueden acceder a
datos que no sean estticos.
Para entender el uso y funcionamiento de un mtodo static por
ejemplo podemos calcular la raz cuadrada de 900 con una llamada
al mtodo static:
Math.sqrt(900)
Y para imprimir en consola escribimos:
System.out.println(Math.sqrt(900));
Y se mostrar en pantalla 30.
Como vemos no hubo necesidad de crear un objeto Math antes de
llamar al mtodo sqrt.
Otro mtodo static que pertenece a Math es pow:
pow(3,2); devuelve 3^2 =9
Constantes PI y E de la clase Math:

En la clase Math tambin encontramos constantes matemticas de


uso comn: Math.PI y Math.E (PI = 3.141592, E = 2.718281).
Estos campos se declaran en la clase Math con los modificadores
public, final y static. Al hacerlos public, otros programadores
pueden usar estos campos en sus propias clases. Cualquier campo
declarado con la palabra final es constante, es decir su valor no
puede modificarse despus de inicializar el campo. Al hacer a estos
campos static, se puede acceder a ellos mediante el nombre de la
clase y el punto justo igual que los mtodos de instancia.
Por qu el mtodo main se declara como static?
Cuando ejecutamos la JVM, esta JVM trata de invocar al mtodo
main de la clase que le especifico; cuando no se han creado objetos
de esa clase. Al declarar a main como static, la JVM puede invocar a
main sin tener que crear una instancia de la clase.
Es decir si luego de crear una nueva clase que contiene el mtodo
main esttico y si luego ejecuto dicha clase la JVM ejecuta el
mtodo main inmediatamente sin necesidad de esperar que haya
una instancia de dicha clase.
Adems podemos colocar un mtodo main en cada clase que
declare. La JVM invoca solo al mtodo main en la clase que se
utiliz para ejecutar la aplicacin. TIP: algunos programadores
usan esto para crear un pequeo programa de prueba en cada
clase que declaran.
c. Clases static
La palabra static, solo puede ser usada en clases cuando esta es
una clase anidada. Por ejemplo lo siguiente es invlido:
public static class Persona{ }
Por lo tanto solo pueden ser utilizadas dentro de otra clase, lo
siguiente es vlido:
public class Persona{
public static class{ } }

PALABRA final
a. final en la declaracin de un atributo
Cualquier atributo o campo declarado con la palabra final es
constante, es decir su valor no puede modificarse despus de
inicializar el campo.

b. final en la declaracin de un mtodo


Cualquier mtodo declarado con la palabra final indica que el
mtodo no puede ser redefinido o sobre escrito por alguna
subclase.
c. final en la declaracin de una clase
Cualquier clase que lleva final en su declaracin indica que la clase
no puede ser heredada. Obviamente no puede ser lo siguiente:
public abstract final class Personal

VARIABLES
a. Variables Locales
Dentro del cuerpo de un mtodo se puede declarar ms variables
para usarlas dentro del mtodo.
Estas variables son variables locales y viven slo mientras el
control permanezca dentro del mtodo.

Anda mungkin juga menyukai