1: using System;
2: using System.Collections;
3: using System.Collections.Generic;
4:
5: namespace DemoObjeto5
6: {
7: /// <summary>
8: /// Definición para aquellos objetos que presentan el comportamiento
9: /// asociado con una "bolsa" que contine "elementos", en la bolsa se
10: /// puede agregar o sacar elementos, tambiéne es posible averiguar si
11: /// está vacía, o cuantos elementos tiene en total así como cuantos
12: /// elementos de algun valor hay.
13: ///
14: /// Implementa la bolsa para objetos de cualquier tipo !!!
15: ///
16: /// </summary>
17: public class Bolsa <ELEMENTO>
18: {
19:
20: #region Campos de la Estructura Interna de cada objeto
21:
22: /// <summary>
23: /// sirve para almacenar o guardar los elementos dentro del objeto
24: /// inicialmente tiene una capacidad para 100 caracteres.
25: /// </summary>
26: protected ArrayList datos;
27:
28: #endregion
29:
30: #region Constructores
31:
32: /// <summary>
33: /// Constructor por defecto, incializa los elementos de la estructura
34: /// interna del objeto.
35: /// </summary>
36: public Bolsa()
37: {
38: datos = new ArrayList(100);
39: }
40:
41: /// <summary>
42: /// Constructor especializado, permite indicar el tamaño o dimensión
43: /// del contenedor (arreglo) para los elementos de la Bolsa.
44: /// </summary>
45: /// <exception cref="ArgumentException">
46: /// Dispara la excepción de argumento inválido cuando el parametro es cero o menor
47: /// </exception>
48: /// <param name="dimension">Tamaño incial del contenedor (debe ser mayor que cero)</param>
49: public Bolsa(int dimension)
50: {
51: if (dimension > 0)
52: {
53: datos = new ArrayList(dimension);
54: }
55: else
56: {
57: throw new ArgumentException("Argumento incorrecto, dimension = " + dimension.ToString());
58: }
59: }
60:
61: /// <summary>
62: /// Constructor especializado, permite crear un objeto como copia de otra
63: /// </summary>
64: /// <exception cref="ArgumentException">
65: /// Dispara la excepción de argumento inválido cuando el parametro es nulo o
66: /// no es del tipo Bolsa
67: /// </exception>
68: /// <param name="origen">objeto del tipo Bolsa que se copia</param>
69: public Bolsa(Bolsa<ELEMENTO> origen)
70: {
71: if ((origen != null) && (origen is Bolsa<ELEMENTO>))
72: {
73: datos = new ArrayList(origen.Contar());
74:
75: for (int i = 0; i < origen.Contar(); ++i)
76: {
77: // ESTO SOLAMENTE COPIA LA REFERENCIA AL OBJETO
78: datos[i] = origen.datos[i];
79: }
80: }
81: else
82: {
83: throw new ArgumentException("Argumento incorrecto, origen = null");
84: }
85: }
86:
87: #endregion
88:
89:
90: #region Métodos públicos, implementan los mensajes
91:
92: /// <summary>
93: /// Agrega un elemento al objeto del tipo bolsa
94: /// </summary>
95: /// <param name="x">Elemento que se desea agregar</param>
96: /// <returns>Referencia al mismo objeto bolsa que ahora continene el nuevo elemento</returns>
97: public virtual Bolsa<ELEMENTO> Agregar(ELEMENTO x)
98: {
99: datos.Add(x);
100: return this;
101: }
102:
103: /// <summary>
104: /// Cuenta cuántos elementos hay en un objeto del tipo bolsa
105: /// </summary>
106: /// <returns>Cantidad de elementos que hay en el objeto bolsa</returns>
107: public int Contar()
108: {
109: return datos.Count;
110: }
111:
112: /// <summary>
113: /// Cuenta cuántos elemetnos de un determinado valor se encuentran dentro
114: /// de un objeto del tipo bolsa
115: /// </summary>
116: /// <param name="x">Valor que se desea averiguar</param>
117: /// <returns>Cantidad de elementos del valor dado que hay en el objeto bolsa</returns>
118: public int Contar(ELEMENTO x)
119: {
120: int cuenta = 0;
121: for (int i = 0; i < datos.Count; ++i)
122: {
123: // Es necesario utilizar el mensaje Equals
124: if (datos[i].Equals(x))
125: {
126: ++cuenta;
127: }
128: }
129: return cuenta;
130: }
131:
132: /// <summary>
133: /// Averigua si un elemento está o no dentro de un objeto del tipo bolsa
134: /// </summary>
135: /// <param name="x">Elemento que se desea controlar</param>
136: /// <returns>Verdadero si el elemento está en la bolsa, caso contrario falso</returns>
137: public bool Existe(ELEMENTO x)
138: {
139: return datos.Contains(x);
140: }
141:
142: /// <summary>
143: /// Saca o retira el elemento indicado del objeto del tipo bolsa,
144: /// </summary>
145: /// <param name="x">Elemento a retirar o sacar</param>
146: /// <returns>Referencia al miso objeto bolsa sin el elemento indicado</returns>
147: public Bolsa<ELEMENTO> Sacar(ELEMENTO x)
148: {
149: if (Existe(x))
150: {
151: datos.Remove(x);
152: }
153: return this;
154: }
155:
156: /// <summary>
157: /// Genera una cadena con todos los elementos que hay en el objeto
158: /// del tipo bolsa.
159: /// </summary>
160: /// <remarks>
161: /// ESTA NO ES LA MEJOR IMPLEMENTACIÓN, PERO SIRVE PARA EL EJEMPLO
162: /// DEBERÍA UTILIZARSE UN OBJETO StringBuilder (luego lo veremos)
163: /// </remarks>
164: /// <returns>Cadena con la representación de cada elemento que hay en el objeto bolsa</returns>
165: public override string ToString()
166: {
167: string s = "";
168: for (int i = 0; i < datos.Count; ++i)
169: {
170: s = s + "\n\t" + datos[i].ToString() + " ";
171: }
172: return s;
173: }
174:
175:
176: /// <summary>
177: /// Determina si el objeto (Bolsa) es igual al objeto que se pasa
178: /// como argumento. La única posibilidad es que el argumento también
179: /// sea del tipo Bolsa.
180: /// </summary>
181: /// <param name="obj">Objeto con el que se compara</param>
182: /// <returns>verdadero si ambos objetos son iguales</returns>
183: public override bool Equals(object obj)
184: {
185: if ((obj != null) && (obj is Bolsa<ELEMENTO>))
186: {
187: return Equals((Bolsa<ELEMENTO>)obj);
188: }
189: return false;
190: }
191:
192: /// <summary>
193: /// Generá un número, mediante técnicas hash que se corresponde con el
194: /// contenido interno del objeto.
195: /// </summary>
196: /// <returns>Valor del código hash</returns>
197: public override int GetHashCode()
198: {
199: return base.GetHashCode();
200: }
201:
202: /// <summary>
203: /// Determina si el objeto del tipo Bolsa es igual a la bolsa que se
204: /// pasa como argumento.
205: /// Todos los elementos de una bolsa deben existir en la otra bolsa,
206: /// el control debe realizarse en ambas para superar el siguiente caso
207: /// bolsa1 = ['A', 'B', 'B']
208: /// bolsa2 = ['A', 'B', 'C']
209: ///
210: /// </summary>
211: /// <param name="otra">Objeto del tipo bolsa con el que se compara</param>
212: /// <returns>Verdadero si ambas bolsas son iguales</returns>
213: public bool Equals(Bolsa<ELEMENTO> otra)
214: {
215: if ((otra != null) && (this.datos.Count == otra.datos.Count))
216: {
217: for (int i = 0; i < this.datos.Count; ++i) // este ciclo controla el objeto emisor
218: {
219: if (!otra.Existe((ELEMENTO)this.datos[i]))
220: {
221: return false;
222: }
223: }
224: for (int i = 0; i < otra.datos.Count; ++i) // este ciclo controla el objeto parámetro
225: {
226: if (!this.Existe((ELEMENTO)otra.datos[i]))
227: {
228: return false;
229: }
230: }
231: return true;
232: }
233: return false;
234: }
235:
236: #endregion
237:
238: #region Iteradores (a mano)
239:
240: /// <summary>
241: /// Implementación del método que obtiene un enumerador del objeto
242: /// Esto se utiliza internamente en las sentencias foreach(...)
243: /// </summary>
244: /// <returns>Referencia al código que implementa el enumerador</returns>
245: public IEnumerator<ELEMENTO> GetEnumerator()
246: {
247: return MiEnumerador();
248: }
249:
250: /// <summary>
251: /// Implementación propia de un enumerado para permitir el uso de la
252: /// sentencia foreach(...) con objetos del tipo Bolsa
253: /// Utiliza la sentencia yield para entregar los elementos de uno
254: /// </summary>
255: /// <returns>Cada elemento de la bolsa de uno de por vez</returns>
256: private IEnumerator<ELEMENTO> MiEnumerador()
257: {
258: for (int i = 0; i < datos.Count; ++i)
259: {
260: yield return (ELEMENTO)datos[i];
261: }
262: }
263:
264: #endregion
265:
266: }
267: }