Tengo una clase existente que interactúa y que puede abrir, leer o escribir en un archivo. Necesito recuperar una modificación de archivo para ese propósito. Tengo que agregar un nuevo método.
Supongamos que lo siguiente es mi definición de clase donde quiero agregar un nuevo método.
class IO_file
{
std::string m_file_name;
public:
IO();
IO(std::string file_name);
+ time_t get_mtime(file_name);
+ OR
+ time_t get_mtime();
};
Tengo dos opciones
Cree un objeto vacío y luego pase el nombre_archivo en el argumento del método para el que deseo recuperar la hora de modificación del archivo.
Pase el nombre del archivo en la construcción del objeto y simplemente llame a la función miembro que operará en la variable miembro.
Ambas opciones servirán para el propósito. También creo que el segundo enfoque es mejor que el primero. Pero lo que no entiendo es ¿Cómo ? ¿El primer enfoque es un mal diseño ya que no utiliza una variable miembro? ¿Qué principio de diseño orientado a objetos viola? Si una función miembro no usa la variable miembro, ¿esa función miembro siempre debe hacerse estática?
IO("somefile.txt").get_mtime("someotherfile.txt")
. ¿Y eso que significa?Respuestas:
No.
OOP no le importa si su función miembro usa, o no usa, propiedades de clase o variables miembro. OOP se preocupa por el polimorfismo y no por la implementación de codificación dura. Las funciones estáticas tienen sus usos, pero una función no debería ser estática simplemente porque no depende del estado del objeto. Si eso es lo que piensas bien, pero no culpes a OOP porque esa idea no vino de OOP.
Si no necesita recordar el estado de una llamada a otra, no hay una buena razón para usar el estado.
Ninguna.
No. Este pensamiento tiene la flecha de implicación que va en la dirección equivocada.
Una función estática no puede acceder al estado de la instancia
Si la función no tiene necesidad de acceder al estado de instancia, entonces la función puede ser estática o no estática
Hacer que la función sea estática aquí depende completamente de usted. Pero lo hará más como un global si lo hace. Antes de volverse estático, considere alojar la función en una clase sin estado. Es mas flexible.
Tengo aquí un ejemplo de OOP de una función miembro que no usa propiedades de clase o variables miembro.
La función miembro (y su clase sin estado) :
Tres implementaciones diferentes:
Un lugar para almacenar la elección de implementación:
Un ejemplo de uso
Salidas:
Y todo sin
execute()
preocuparse por el estado de ningún objeto. LaStrategy
clase en realidad no tiene estado. Solo el estado está adentroContext
. Los objetos sin estado están perfectamente bien en OOP.Encontré este código aquí .
fuente
get_mtime
tendría más sentido aquí como una función independiente o como unastatic
función, en lugar de como se ha mostrado aquí.La
mtime
lectura de un archivo se lee, en la mayoría de los sistemas, desde una llamadalstat
o similar, y no requiere un descriptor de archivo abierto, por lo que no tiene sentido tenerlo como una función miembro de una clase instanciada.fuente
static
miembro.La razón por la que la segunda opción parece instintivamente mejor (y, IMO, ES mejor) es porque su primera opción le da un objeto que en realidad no representa nada.
Al no especificar el nombre de archivo, su clase IO_file es realmente solo un objeto abstracto que se parece a un archivo concreto. Si está pasando el nombre del archivo cuando llama al método, también puede refactorizar todo el método en una función pura flotante; no hay ningún beneficio real para mantenerlo atado a un objeto que necesitará instanciar solo para usarlo. Es solo una función; la repetitiva de creación de objetos es solo un paso inconveniente agregado.
Por otro lado, una vez que se le da el nombre de archivo, cualquier método que llame a ese objeto se parece más a consultas sobre una instancia específica de una cosa. Eso es mejor OO porque sus objetos tienen un significado real y, por lo tanto, utilidad.
fuente
Traduzcamos esto a C. Primero, nuestra clase, ahora es una estructura:
Definamos, por simplicidad de los fragmentos, una función de constructor (ignorando las pérdidas de memoria por ahora):
La opción 2 se ve así:
y usado así:
¿Qué tal la opción # 1? Bueno, se ve así:
¿Y cómo se usa? Esencialmente, está pidiendo pasar basura como primer parámetro:
No tiene mucho sentido, ¿verdad?
El sistema de objetos de C ++ lo oculta, pero el objeto también es un argumento del método, un argumento puntero implícito llamado
this
. Esto es lo que la opción n. ° 1 es mala: tiene un argumento que no se usa por definición (los argumentos que no se usan, pero pueden usarse en anulaciones están bien). Tales argumentos no aportan nada mientras complican la firma, la definición y el uso de la función y confunden a los lectores del código que se quedan reflexionando sobre lo que se supone que debe hacer el argumento, por qué está bien pasarle basura y si el hecho de que usted es o no pasarle basura /NULL
/ objeto vacío es la causa del error que actualmente están tratando de resolver. Spoiler: no lo es, pero todavía van a perder el tiempo explorando esa posibilidad.El hecho de que el argumento basura sea implícito puede disminuir el efecto, pero todavía está ahí y puede evitarse fácilmente haciendo el método
static
.fuente