Skip to content

Commit 5ae6dde

Browse files
committed
Añade epígrafe sobre patrones de diseño
1 parent c478871 commit 5ae6dde

File tree

9 files changed

+264
-26
lines changed

9 files changed

+264
-26
lines changed

source/01.archivos/01.gestion.rst

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ Para acceder a las variables de entorno, *Java* dispone del método estático\
4848
Map<String, String> entorno = System.getenv();
4949
entorno.get("HOME"); // /home/usuario, de nuevo.
5050
51-
El **problema** crucial de consultar las variables de entorno es el de que el
52-
nombre cambia entre los distintos sistemas operativos\ [#]_ y, por tanto, si nos
53-
limitamos a usarlas tal como acabamos de ver, nuestra aplicación será
54-
dependiente del sistema en que se ejecute.
51+
El **problema** de consultar variables de entorno es que su existencia y sus
52+
nombres dependen del sistema operativo\ [#]_, por lo que, si nos limitamos a
53+
usarlas como acabamos de ver, la aplicación será dependiente del
54+
sistema sobre el que se ejecute e incumpliremos nuestro propósito de
55+
independizar la aplicación de la plataforma.
5556

5657
.. _system-properties:
5758

58-
Una alternativa es consultar las propiedades de nuestro entorno de *Java*,
59+
Una *alternativa* es consultar las propiedades de nuestro entorno de *Java*,
5960
algunas de las cuales recogen los valores de las variables de entorno:
6061

6162
``System.getProperty(String nombre_propiedad)``
@@ -240,6 +241,18 @@ podemos hacer construcciones como esta:
240241
.. attention:: Con estas herramientas sólo construimos rutas, así que tales rutas
241242
no tienen por qué existir.
242243

244+
.. admonition:: Conclusión
245+
246+
Debemos siempre independizar el código de la plataforma subyacente para lo
247+
cual debemos:
248+
249+
a. Construir las rutas con las herramientas proporcionadas por *Java*.
250+
#. Intentar utilizar las :ref:`propiedades del sistema
251+
<system-properties>` para resolver las particularidades.
252+
#. En caso de no que no baste con ellas será necesario obtener la plataforma\
253+
[#]_ y crear código condicional que implemente la solución dependiendo
254+
cuál sea.
255+
243256
.. _file.files:
244257

245258
Gestión
@@ -321,10 +334,10 @@ dentro de él. Los dos últimos argumentos son opcionales.
321334

322335
Manipulación
323336
------------
324-
Por manipulación entendemos, simplemente, la copia y traslado de archivos o el
325-
cambio de sus propiedades (permisos, propietarios, etc) y no la alteración del
326-
contenido, que reservamos para el :ref:`próximo epígrafe sobre manipulación
327-
<manipulacion-archivos>`.
337+
Por :dfn:`manipulación` entendemos, simplemente, la copia y traslado de archivos
338+
o el cambio de sus propiedades (permisos, propietarios, etc) y no la alteración
339+
del contenido, que reservamos para el :ref:`próximo epígrafe sobre manipulación
340+
de contenidos <manipulacion-archivos>`.
328341

329342
Para **crear** un archivo:
330343

@@ -333,7 +346,7 @@ Para **crear** un archivo:
333346
Files.createFile(home.resolve("caca.txt"));
334347
335348
lo que creará el archivo vacío :file:`caca.txt` dentro de nuestro directorio
336-
natural con los permisos que determine la máscara del sistema. Podríamos haber
349+
personal con los permisos que determine la máscara del sistema. Podríamos haber
337350
definido otros permisos, pero para ello tendríamos que haber incluido argumentos
338351
adicionales (véase :java-nio:`FileAttribute <attribute/FileAttribute>`), pero no
339352
entraremos en tanto detalle. También existe ``Files.createDirectory(Path dir)``
@@ -345,9 +358,9 @@ Podemos también copiar, mover o borrar archivos:
345358
346359
Path tmp = Path.of(System.getProperty("java.io.tmpdir"));
347360
Path caca = home.resolve("caca.txt");
348-
Files.copy(caca, tmp.resolve("caca.txt")); // Copia en /tmp/kk.txt
349-
Files.move(caca, tmp.resolve("caca.txt")); // Error, el destino ya existe.
350-
Files.move(caca, tmp.resolve("caca.txt"), StandardCopyOption.REPLACE_EXISTING);
361+
Files.copy(caca, tmp.resolve("kk.txt")); // Copia en /tmp/kk.txt
362+
Files.move(caca, tmp.resolve("kk.txt")); // Error, el destino ya existe.
363+
Files.move(caca, tmp.resolve("kk.txt"), StandardCopyOption.REPLACE_EXISTING);
351364
Files.delete(caca);
352365
353366
.. tip:: También se pueden copiar flujos (:java-io:`InputStream <InputStream>`)
@@ -360,7 +373,8 @@ contenido, pero los dejamos para el siguiente epígrafe.
360373

361374
.. caution:: A diferencia de lo que ocurre al usar en una terminal las órdenes
362375
:ref:`cp <linux:cp>` o :ref:`mv <linux:mv>`, no basta con poner el directorio
363-
de destino, cuando queremos conservar el nombre original.
376+
de destino, aunque queramos conservar el nombre original: siempre debe
377+
escribirse la ruta completa, incluido el nombre del archivo de destino.
364378

365379
.. warning:: Por supuesto, estas acciones pueden generar excepciones (p.ej. al
366380
intentar crear un archivo dentro de un directorio en el que no tenemos
@@ -377,6 +391,9 @@ contenido, pero los dejamos para el siguiente epígrafe.
377391
378392
System.getenv("HomeDrive") + System.getenv("HomePath");
379393
394+
.. [#] Por ejemplo, ``System.getProperty("os.name")`` devuelve el nombre del
395+
sistema operativo.
396+
380397
.. |API| replace:: :abbr:`API (Application Programming Interface)`
381398
.. |MIME| replace:: :abbr:`MIME (Multipurpose Internet Mail Extensions)`
382399
.. |URI| replace:: :abbr:`URI (Uniform Resource Identifier)`

source/98.apendices/05.pattern.rst

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
.. _design-patterns:
2+
3+
Patrones de diseño
4+
******************
5+
Un :dfn:`patron de diseño` es una plantilla de codificación que se ha demostrado
6+
eficaz para resolver un problema habitual. Es útil conocerlos, porque si en
7+
nuestro programa nos enfrentamos a un problema que ya ha sido resuelto mediante
8+
uno de estos patrones, podremos ponerlo en práctica.
9+
10+
En este apéndice, explicaremos algunos que
11+
12+
.. _singleton-pattern:
13+
14+
Singleton
15+
=========
16+
Es un patrón que garantiza que de una clase sólo pueda existir una única
17+
instancia.
18+
19+
Puede sernos muy útil,por ejemplo, si creamos una aplicación constituida por
20+
diversos paquetes y queremos que la configuración esté disponible en todos ellos
21+
sin tener que pasar constantemente los parámetros de configuración.
22+
23+
Caso simple
24+
-----------
25+
En Java se implementa así:
26+
27+
.. literalinclude:: files/Singleton.java
28+
:language: java
29+
:start-at: public class
30+
31+
Es decir, básicamente ocultamos el constructor para que la instancia sólo sea
32+
accesible a través del método estático ``.getInstance``. De este modo, la única
33+
forma de acceder al constructor es a través de ``.initialize``, pero sólo
34+
podremos inicializar una vez.
35+
36+
.. tip:: Una variante de este patrón es que queramos crear no una instancia,
37+
sino varias, dependiendo del valor de uno de los argumentos. En ese caso, el
38+
atributo ``instance`` se puede convertir en un mapa cuyas claves son
39+
esos valores.
40+
41+
Programas multihilo
42+
-------------------
43+
En caso de que nuestro programa sea multihilo entonces tendremos que complicar
44+
un poco el código:
45+
46+
.. literalinclude:: files/Singleton-synchro.java
47+
:language: java
48+
:start-at: public class
49+
50+
51+
.. _factory-pattern:
52+
53+
*Factory*
54+
=========
55+
El :dfn:`patrón Factory` es un patrón utilizado para creación de objetos que se
56+
utiliza para poder escoger en tiempo de ejecución qué objeto crear entre varios
57+
que cumplen con una misma interfaz (o pertenecen a subclases de una misma
58+
clase).
59+
60+
Implementación
61+
--------------
62+
Para ilustrarlo imaginemos que en nuestra aplicación necesitamos traducir datos
63+
a distintos formatos. En una traducción básicamente hay dos operaciones:
64+
65+
* *Leer*, que consiste en convertir la información que está almacenada en un
66+
determinado formato en datos internos del programa.
67+
* *Escribir*, que consiste transformar los datos internos al formato
68+
especificado.
69+
70+
Por tanto, queramos traducir a lo que queramos traducir, la clase reponsable
71+
de la traducción tendrá que implementar la siguiente interfaz:
72+
73+
.. literalinclude:: files/Traductor.java
74+
:language: java
75+
:class: toggle
76+
:start-at: public interface
77+
78+
en la que hemos supuesto que los datos los almacenamos en memoria en forma de
79+
una lista. Hemos considerado una lista del ``Object`` genérico, aunque en un
80+
ejemplo real concreto la lista será de alguna clase que hayamos definido. El
81+
caso es que ahora definiremos diferentes clases las cuales implementarán esta
82+
interfaz para distintos formatos (:ref:`XML <xml>`, :ref:`CSV <csv>`, :ref:`JSON
83+
<json>`, etc.). Imaginemos que las clases se denominan ``TXml``, ``TCvs``,
84+
``TJson``, etc.
85+
86+
Con todo esto, podemos poner en práctica este patrón así:
87+
88+
.. literalinclude:: files/TraductorFactory.java
89+
:language: java
90+
:start-at: public class
91+
92+
En definitiva, la clase tiene un método estático que se limita a devolver el
93+
objeto de traducción apropiado según sea el formato. En el código principal no
94+
habrá más que hacer lo siguiente:
95+
96+
.. code-block:: java
97+
98+
// El formato se proporcionará de alguna manera...
99+
String formato = "json";
100+
101+
Traductor traductor = TraductorFactory.crearTraductor(formato);
102+
103+
// Suponiendo que en "data" estén los datos, esto generará una salida JSON.
104+
traductor.escribir(System.out, data);
105+
106+
Obsérvese que el código de ``TraductorFactory`` depende de qué clases
107+
traductoras hallamos creado realmente; y, si se crea una nueva (o se elimina una
108+
ya creada por algún motivo), habrá que editar la clase para que se refleje este
109+
cambio. El siguiente apartado complica un poco la implementación, pero permite
110+
escribir una clase sin esta dependencia, de manera que podemos reaprovecharla,
111+
sea cual sea el caso.
112+
113+
Automatización
114+
--------------

source/98.apendices/99.ide.rst

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ Visual Studio Code
44
******************
55
.. note:: La mayor parte de las instrucciones generales para el |IDE| están
66
fusiladas muy indisimuladamente del :ref:`apéndice correspondiente
7-
<lm:vscode>` de los :ref:`apuntes para el módulo de Lenguajes de Marcas <lm:mod-lm>`.
7+
<lm:vscode>` de los :ref:`apuntes para el módulo de Lenguajes de Marcas <lm:apuntes-lm>`.
88

99
Como entorno de desarrollo para el seguimiento del módulo recomendamos `Visual
10-
Studio Code`_, el cual es un |IDE|, con innumerables extensiones, especialmente
11-
diseñado para la escritura de código, y con versiones para los principales
12-
sistemas operativos. Esta disponible para su descarga gratuita en su página web
13-
y su código fuente en `su página de GitHub
14-
<https://github.com/microsoft/vscode>`_.
10+
Studio Code`_, por varios motivos:
11+
12+
* Es *software* libre (`licencia MIT <https://es.wikipedia.org/wiki/Licencia_MIT>`_) y
13+
está dispoible para su descarga gratuita en su página web y su código fuente
14+
en `su página de GitHub <https://github.com/microsoft/vscode>`_.
15+
* Está especialmente diseñado para la escritura de código y dispone de
16+
innumerables extensión que le dan soporte para muchos lenguajes de
17+
programación.
18+
* Tiene versiones en los principales sistemas operativos.
1519

1620
Generalidades
1721
=============
@@ -61,7 +65,7 @@ archivos de configuración |JSON|:
6165
cuales se corresponde con un distinto *perfil de desarrollador*. Esto es
6266
debido a que, cuando programamos por ejemplo en *Python*, no necesitamos
6367
exactamente el mismo entorno de desarrollo que cuando programamos en
64-
Javascript*. En consecuencia necesitaremos unas extensiones distintas,
68+
*Javascript*. En consecuencia necesitaremos unas extensiones distintas,
6569
unas preferencias distintas, etc. :program:`Visual Studio Code` nos
6670
permite lidiar con estas diferencias, permitiendo crear distintos
6771
*perfiles*, que escogeremos a voluntad dependiendo qué pretendamos
@@ -158,7 +162,28 @@ archivos de configuración |JSON|:
158162
Este tipo de personalización puede hacerse tanto `a nivel de perfil`_
159163
como de `área de trabajo`_. Como
160164
alternativa, podemos directamente editar los :file:`settings.json`
161-
correspondientes.
165+
correspondientes. Para ello puede pulsarse sobre el icono remarcado arriba a
166+
la derecha.
167+
168+
.. _vscode-utf8-term-win:
169+
170+
Por ejemplo, es común que utilicemos UTF-8 para la codificación de caracteres
171+
y, si usamos Windows, nos encontraremos con el inconveniente que la terminal
172+
de éste no utilice esta codificación. Para paliarlo podemos añadir:
173+
174+
.. code-block:: json
175+
176+
{
177+
"terminal.integrated.profiles.windows": {
178+
"PowerShell": {
179+
"source": "PowerShell",
180+
"icon": "terminal-powershell",
181+
"args": ["-NoExit", "-Command", "chcp 65001"]
182+
},
183+
},
184+
"terminal.integrated.defaultProfile.windows": "PowerShell"
185+
}
186+
162187
163188
.. _vscode-extensions:
164189

@@ -374,6 +399,9 @@ aquellas configuraciones que deseemos que sean universales independientemente de
374399
la herramienta que utilicemos. En particular, nos puede interesar:
375400

376401
+ La :ref:`configuración del idioma <vscode-language>`.
402+
+ Si trabajamos en *Windows* y creamos aplicaciones que utilizan como interfaz
403+
de usuario la consola, :ref:`configurar la codificación de ésta para que sea
404+
UTF-8 <vscode-utf8-term-win>`.
377405
+ Los aspectos relacionados con el editor (tamaño de la fuente, `emulación de
378406
vim <https://marketplace.visualstudio.com/items?itemName=vscodevim.vim>`_).
379407
+ Los :ref:`atajos generales de teclado <vscode-atajos>`.
@@ -764,7 +792,7 @@ extensión `Maven for Java`_:
764792

765793
Ejecución
766794
---------
767-
Ya hemos dicho que para ejecutar la aplicación podemos pulsar:kbd:`Ctrl`\ +
795+
Ya hemos dicho que para ejecutar la aplicación podemos pulsar :kbd:`Ctrl`\ +
768796
:kbd:`F5` (si no queremos atender a los puntos de ruptura que hayamos definido)
769797
o, simplemente, :kbd:`F5` si sí queremos hacerlo y depurar el programa paso a
770798
paso. Además, podemos instruir al |IDE| de cómo ejecutar el programa dándole
1.03 KB
Loading
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import java.io.ObjectInputFilter.Config;
2+
import java.util.Map;
3+
4+
public class Singleton {
5+
private static volatile Singleton instance;
6+
7+
// Posiblemente haya atributos de instancia (y sus correspondintes getters)
8+
9+
private Singleton(Map<String, String> args) {
10+
// Utilizamos los argumentos para
11+
// definir los valores de los atributos
12+
}
13+
14+
public static Singleton initialize(Map <String, String> args) {
15+
if(instance == null) {
16+
synchronized (Config.class) {
17+
if(instance == null) {
18+
instance = new Singleton(args);
19+
return instance;
20+
}
21+
}
22+
}
23+
throw new IllegalStateException("La instancia ya fue inicializada");
24+
}
25+
26+
public static Singleton getInstance() {
27+
if(instance == null) throw new IllegalStateException("La instancia no está inicializada: use .initialize");
28+
return instance;
29+
}
30+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import java.util.Map;
2+
3+
public class Singleton {
4+
private static Singleton instance;
5+
6+
// Posiblemente haya atributos de instancia (y sus correspondintes getters)
7+
8+
private Singleton(Map<String, String> args) {
9+
// Utilizamos los argumentos para
10+
// definir los valores de los atributos
11+
}
12+
13+
public static Singleton initialize(Map <String, String> args) {
14+
if(instance == null) {
15+
instance = new Singleton(args);
16+
return instance;
17+
}
18+
throw new IllegalStateException("La instancia ya fue inicializada");
19+
}
20+
21+
public static Singleton getInstance() {
22+
if(instance == null) throw new IllegalStateException("La instancia no está inicializada: use .initialize");
23+
return instance;
24+
}
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public interface Traductor {
2+
// Posiblemente sea una lista de un tipo determinado, no el genérico Object.
3+
public List<Object> leer(InputStream st) throws IOException;
4+
public void escribir(OutputStream st, List<Object> data) throws IOException;
5+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public class TraductorFactory {
2+
3+
public static Traductor crearTraductor(String formato)
4+
throws IllegalArgumentException, UnsupportedOperationException {
5+
6+
return switch (formato.toLowerCase()) {
7+
// Formatos implementados
8+
case "txt" -> new TTxt();
9+
case "csv" -> new TCsv();
10+
case "json" -> new TJson();
11+
case "yaml" -> new TYaml();
12+
// Formatos conocidos que no se han implementado
13+
case "xml" -> throw new UnsupportedOperationException(String.format("'%s': Formato no soportado.", formato));
14+
// Cualquier otra cosa, no es un formato que reconozcamos
15+
default -> throw new IllegalArgumentException(String.format("'%s': Formato desconocido.", formato));
16+
};
17+
}
18+
}

source/index.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ Acceso a datos
1818

1919
.. rubric:: Normativa específica.
2020

21-
* `Real Decreto 450/2010`_, que establece el título.
22-
* `Real Decreto 405/2023`_, que modifica el anterior actualizando sus módulos.
21+
* `Real Decreto 450/2010`_, que establece el título y al cual actualiza el
22+
currículo de sus módulos el `Real Decreto 405/2023`_.
2323
* `Real Decreto 500/2024`_, que compatibiliza el currículo de los ciclos
2424
formativos de grado superior con el `Real Decreto 659/2023`_ de 18 de julio, que
2525
desarrolla la `Ley Orgánica 3/2022`_.
26-
* `Orden de 16 de junio de 2011`_, que transpone en la Comunidad Autónoma de Andalucía el Real Decreto.
26+
* `Orden de 16 de junio de 2011`_, que transpone en la Comunidad Autónoma de
27+
Andalucía el Real Decreto.
2728

2829
.. rubric:: Contenidos del curso
2930

0 commit comments

Comments
 (0)