¿Cuánto trabajo debe hacer el constructor para una clase de análisis HTML?


¿Cuánto trabajo es razonable para un constructor de objetos? ¿Debería simplemente inicializar los campos y no realizar ninguna operación en los datos, o está bien que realice algún análisis?

Antecedentes: Estaba escribiendo una clase que es responsable de analizar una página HTML y devolver información diversa basada en la información analizada. El diseño de la clase es tal que el constructor de la clase hace el análisis, lanzando una excepción si ocurre un error. Una vez la instancia se inicializa, los valores analizados están disponibles sin procesamiento adicional a través de los accesores. Algo como:

public class Parser {

    public Parser(final String html) throws ParsingException {
        /* Parsing logic that sets private fields */
        /* that throws an error if something is erroneous.*/
    }

    public int getNumOfWhatevers() { return private field; }
    public String getOtherValue()  { return other private field; }
}

Después de diseñar la clase empecé a preguntarme si esta era la práctica correcta. ¿El código de análisis debe colocarse dentro de un método void parseHtml() y los accesores solo devuelven valores válidos una vez que se llama a este método? Siento que mi implementación es correcta, pero no puedo evitar sentir que algunos puristas de OO podrían encontrarlo incorrecto por alguna razón y que un una aplicación como la siguiente sería mejor:

public class Parser {

    public Parser(final String html) {
        /* Remember html for later parsing. */
    }

    public void parseHtml() throws ParsingException { 
        /* Parsing logic that sets private fields */
        /* that throws an error if something is erroneous.*/
    }

    public int getNumOfWhatevers() { return private field; }
    public String getOtherValue()  { return other private field; }
}

¿Hay casos en los que el código de inicialización, como el análisis de información, no debería ocurrir dentro del constructor, o simplemente estoy siendo tonto y cuestionándome a mí mismo?

¿Cuáles son los beneficios/inconvenientes de dividir el análisis del constructor?

Pensamientos? Insights?

Author: Benoit, 2009-07-26

19 answers

Normalmente sigo un principio fácil:

Todo lo que es obligatorio para la existencia y el comportamiento correctos de la instancia de clase debe pasarse y hacerse en el constructor.

Cualquier otra actividad se realiza por otros métodos.

El constructor nunca debe:

  • use otros métodos de la clase con el propósito de usar el comportamiento de sobreescritura
  • actuar sobre sus atributos privados a través de métodos

Porque aprendí lo difícil de manera que mientras estás en el constructor, el objeto está en un estado intermedio incoherente que es demasiado peligroso para manejar. Parte de este comportamiento inesperado podría esperarse de su código, algunos podrían ser de la arquitectura del lenguaje y las decisiones del compilador. Nunca adivines, mantente a salvo, sé mínimo.

En su caso, usaría un método Parser::parseHTML(archivo). La instanciación del analizador y el análisis son dos operaciones diferentes. Cuando instales un analizador sintáctico, el constructor pone en la condición de realizar su trabajo (análisis). A continuación, se utiliza su método para realizar el análisis. Entonces tienes dos opciones:

  1. O bien permite que el analizador contenga los resultados del análisis, y da a los clientes una interfaz para recuperar la información analizada (por ejemplo, Parser::getFooValue()). Los métodos devolverán Null si aún no ha realizado el análisis, o si el análisis falló.
  2. or your Parser:: parseHTML () returns a ParsingResult instance, containing what the Analizador encontrado.

La segunda estrategia le otorga una mejor granularidad, ya que el analizador ahora es sin estado, y el cliente necesita interactuar con los métodos de la interfaz ParsingResult. La interfaz del analizador sigue siendo elegante y simple. Los componentes internos de la clase Parser tenderán a seguir el patrón de constructor .

Comentas: "Siento como si devolviera una instancia de un analizador que no ha analizado nada (como sugieres), un constructor que ha perdido su propósito. No tiene sentido inicializar un analizador sin la intención de analizar la información. Así que si el análisis va a suceder con seguridad, debemos analizar tan pronto como sea posible e informar y errores temprano, como durante la construcción del analizador? Siento como si inicializar un analizador sintáctico con datos no válidos debería resultar en un error."

En realidad no. Si devuelve una instancia de un Analizador, por supuesto que va a analizar. En Qt, cuando instancies un botón, por supuesto se va a mostrar. Sin embargo, tiene el método QWidget::show() para llamar manualmente antes de que algo sea visible para el usuario.

Cualquier objeto en OOP tiene dos preocupaciones: inicialización y operación (ignorar finalización, no está en discusión en este momento). Si mantiene estas dos operaciones juntas, ambos corren el riesgo de tener problemas (tener un objeto incompleto operando) y pierde flexibilidad. Hay muchas razones por las que realizaría una configuración intermedia de su objeto antes de llamar parseHTML (). Ejemplo: supongamos que desea configurar su analizador para que sea estricto (para que falle si una columna dada en una tabla contiene una cadena en lugar de un entero) o permisivo. O para registrar un objeto de escucha que se advierte cada vez que se realiza o finaliza un nuevo análisis (piense en la barra de progreso de la GUI). Estas son información opcional, y si su arquitectura pone al constructor como el übermethod que hace todo, termina teniendo una enorme lista de parámetros y condiciones de método opcionales para manejar en un método que es intrínsecamente un campo de minas.

"El almacenamiento en caché no debe ser responsabilidad de un analizador sintáctico. Si los datos se van a almacenar en caché, se debe crear una clase de caché separada para proporcionar esa funcionalidad."

Al contrario. Si usted sabe que va a utilizar la funcionalidad de análisis en una gran cantidad de archivos, y hay una posibilidad significativa de que los archivos se va a acceder y analizar de nuevo más adelante, es responsabilidad interna del Analizador para realizar smart almacenamiento en caché de lo que ya vio. Desde la perspectiva del cliente, es totalmente ajeno si este almacenamiento en caché se realiza o no. Él todavía está callling el análisis, y todavía la obtención de un objeto de resultado. pero está recibiendo la respuesta mucho más rápido. Creo que no hay mejor demostración de separación de preocupaciones que esta. Usted aumenta el rendimiento sin absolutamente ningún cambio en la interfaz del contrato o en toda la arquitectura de software.

Sin embargo, tenga en cuenta que no estoy abogando que usted debe nunca use una llamada al constructor para realizar el análisis. Solo digo que es potencialmente peligroso y pierdes flexibilidad. Hay un montón de ejemplos por ahí donde el constructor está en el centro de la actividad real del objeto, pero también hay un montón de ejemplos de lo contrario. Ejemplo (aunque sesgado, surge del estilo C): en python, consideraría muy extraño algo como esto

f = file()
f.setReadOnly()
f.open(filename)

En lugar de la

f = file(filename,"r")

Pero estoy seguro de que hay son bibliotecas de acceso IO que utilizan el primer enfoque (con el segundo como un enfoque de sintaxis de azúcar).

Edit: por último, recuerde que si bien es fácil y compatible agregar en el futuro un "atajo" de constructor, no es posible eliminar esta funcionalidad si lo encuentra peligroso o problemático. Las adiciones a la interfaz son mucho más fáciles que las eliminaciones, por razones obvias. El comportamiento azucarado debe ser ponderado contra el apoyo futuro que usted tiene que proporcionar a ese comportamiento.

 36
Author: Stefano Borini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-27 14:06:20

"¿El código de análisis debe colocarse dentro de un método void parseHTML () y los accesores solo devuelven valores válidos una vez que se llama a este método?"

Sí.

"El diseño de la clase es tal que el constructor de la clase hace el análisis"

Esto evita la personalización, la extensión y, lo más importante, la inyección de dependencias.

Habrá momentos en los que quieras hacer lo siguiente

  1. Construir a analizador.

  2. Agregue Características al analizador: Reglas de Negocio, Filtros, Mejores Algoritmos, Estrategias, Comandos, lo que sea.

  3. Analizar.

Generalmente, es mejor hacer lo menos posible en un constructor para que sea libre de extender o modificar.


Editar

"¿No podrían las extensiones simplemente analizar la información adicional en sus constructores?"

Solo si no tienen ningún tipo de características que necesiten ser inyectado. Si desea agregar características, digamos una estrategia diferente para construir el árbol de análisis, sus subclases también deben administrar esta adición de características antes de analizar. Puede que no sea un simple super() porque la superclase hace demasiado.

"Además, el análisis en el constructor me permite fallar temprano"

Más o menos. Fallar durante la construcción es un caso de uso extraño. Fallar durante la construcción hace que sea difícil construir un analizador como este...

class SomeClient {
    parser p = new Parser();
    void aMethod() {...}
}

Por lo general, un fallo de construcción significa que no tienes memoria. Rara vez hay una buena razón para coger excepciones de construcción porque estás condenado de todos modos.

Se ve obligado a construir el analizador sintáctico en un cuerpo de método porque tiene argumentos demasiado complejos.

En resumen, ha eliminado opciones de los clientes de su analizador.

"Es desaconsejable heredar de esta clase para reemplazar un algoritmo."

Eso es gracioso. Seriamente. Es un una afirmación escandalosa. Ningún algoritmo es óptimo para todos los posibles casos de uso. A menudo, un algoritmo de alto rendimiento utiliza mucha memoria. Un cliente puede querer reemplazar el algoritmo por uno más lento que use menos memoria.

Puedes reclamar perfección, pero es raro. Las subclases son la norma, no una excepción. Alguien siempre mejorará su "perfección". Si limitas su capacidad de subclasificar tu analizador, simplemente lo descartarán por algo más flexible.

"yo no consulte necesidad del paso 2 como se describe en la respuesta."

Una declaración audaz. Las dependencias, las estrategias y los patrones de diseño de inyección relacionados son requisitos comunes. De hecho, son tan esenciales para las pruebas unitarias que un diseño que lo hace difícil o complejo a menudo resulta ser un mal diseño.

Limitar la capacidad de subclase o extender su analizador es una mala política.

Bottom Line .

No asuma nada. Escribir una clase con tan pocas suposiciones sobre ella es casos de uso como sea posible. El análisis en tiempo de construcción hace demasiadas suposiciones sobre los casos de uso del cliente.

 18
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 11:06:27

Un constructor debe hacer lo que sea necesario para poner esa instancia en un estado ejecutable, válido y listo para usar. Si eso significa alguna validación o análisis, yo diría que pertenece allí. Solo ten cuidado con cuánto hace el constructor.

Puede haber otros lugares en su diseño donde la validación también encaja.

Si los valores de entrada provienen de una interfaz de usuario, yo diría que debería ayudar a garantizar una entrada válida.

Si los valores de entrada no están marcados desde un flujo XML entrante, pensaría en usar esquemas para validarlo.

 5
Author: duffymo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:00:30

Probablemente pasaría lo suficiente para inicializar el objeto y luego tendría un método 'parse'. La idea es que las operaciones costosas deben ser lo más obvias posible.

 5
Author: Rodrick Chapman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:01:47

Debe intentar evitar que el constructor haga trabajo innecesario. Al final, todo depende de lo que la clase debe hacer y cómo debe usarse.

Por ejemplo, ¿se llamará a todos los accesores después de construir tu objeto? Si no, entonces ha procesado datos innecesariamente. Además, hay un mayor riesgo de lanzar una excepción "sin sentido" (oh, al intentar crear el analizador, recibí un error porque el archivo estaba mal formado, pero ni siquiera le pedí que analizara nada...)

Pensándolo bien, es posible que necesite el acceso a estos datos rápidamente después de que se compilen, pero puede tardar mucho tiempo en construir el objeto. Podría estar bien en este caso.

De todos modos, si el proceso de construcción es complicado, sugeriría usar un patrón de creación (fábrica, constructor).

 3
Author: Samuel Carrijo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:11:49

Es una buena regla general inicializar solo campos en constructores, y de lo contrario hacer lo menos posible para inicializar el Object. Usando Java como ejemplo, podrías tener problemas si llamas a métodos en tu constructor, especialmente si subclases tu Object. Esto se debe a que, debido al orden de las operaciones en la instanciación de Objetos, las variables de instancia no se evaluarán hasta después de que el super constructor haya terminado. Si intenta acceder al campo durante el super proceso del constructor, lanzará un Exception

Supongamos que tienes una superclase

class Test {

   Test () {
      doSomething();
   }

   void doSomething() {
     ...
   }
 }

Y tienes una subclase:

class SubTest extends Test {
    Object myObj = new Object();

    @Override
    void doSomething() {
        System.out.println(myObj.toString()); // throws a NullPointerException          
    }
 }

Este es un ejemplo específico de Java, y mientras que diferentes lenguajes manejan este tipo de orden de manera diferente, sirve para conducir el punto de inicio.

Edita como respuesta a tu comentario:

Aunque normalmente evitaría los métodos en constructores, en este caso tiene algunas opciones:

  1. En su constructor, establezca la cadena HTML como un campo en su Clase, y analice cada vez que se llamen sus getters. Lo más probable es que esto no sea muy eficiente.

  2. Establezca el HTML como un campo en su objeto, y luego introduzca una dependencia en parse(), con la necesidad de que se llame inmediatamente después de que el constructor haya terminado o incluir algún tipo de análisis perezoso agregando algo como 'ensureParsed()' en la cabeza de sus accesores. No me gusta esto todo eso, ya que podría tener el HTML alrededor después de haber analizado, y su llamada ensureParsed() podría codificarse para establecer todos sus campos analizados, introduciendo así un efecto secundario a su getter.

  3. Puedes llamar a parse() desde tu constructor y correr el riesgo de lanzar una excepción. Como dice, está configurando los campos para inicializar Object, por lo que esto está realmente bien. Con respecto a Exception, afirmar que hubo un argumento ilegal pasado a un constructor es aceptable. Si hace esto, debe tener cuidado de asegurarse de comprender la forma en que su lenguaje maneja la creación de Objetos como se discutió anteriormente. Para seguir con el ejemplo de Java anterior, puede hacer esto sin miedo si se asegura de que solo los métodos private (y por lo tanto no elegibles para overriding by subclasses) se llamen desde dentro de un constructor.

 3
Author: akf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 03:09:59

Misko Hevery tiene una buena historia sobre este tema, desde una perspectiva de pruebas unitarias, aquí.

 3
Author: jqno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 13:26:53

El constructor debe crear un objeto válido. Si en su caso eso requiere leer y analizar información, que así sea.

Si el objeto se puede usar para otros propósitos sin analizar la información primero, considere hacer dos constructores, o un método separado.

 2
Author: Erix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:00:40

Un constructor debe configurar el objeto a utilizar.

Así que sea lo que sea. Eso puede incluir tomar medidas sobre algunos datos o simplemente establecer campos. Cambiará de cada clase.

En el caso de que esté hablando de un Analizador Html, optaría por crear la clase, y luego llamar a un método de análisis Html. La razón de esto es que le da una oportunidad furture para establecer elementos en la clase para analizar el Html.

 1
Author: David Basarab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:01:28

En este caso particular, yo diría que hay dos clases aquí: Un analizador y un resultado de análisis.

public class Parser {
    public Parser() {
        // Do what is necessary to construct a parser.
        // Perhaps we need to initialize a Unicode library, UTF-8 decoder, etc
    }
    public virtual ParseResult parseHTMLString(final string html) throws ParsingException
    {
        // Parser would do actual work here
        return new ParseResult(1, 2);
    }
}
public class ParseResult
{
    private int field1;
    private int field2;
    public ParseResult(int _field1, int _field2)
    {
        field1 = _field1;
        field2 = _field2;
    }
    public int getField1()
    {
        return field1;
    }
    public int getField2()
    {
        return field2;
    }
}

Si su analizador pudiera trabajar en conjuntos parciales de datos, sospecharía que sería adecuado agregar otra clase a la mezcla. Posiblemente un PartialParseResult?

 1
Author: rpetrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 07:14:07

Creo que cuando se crea una clase (obj obj = nueva clase), la clase no debe afectar a la página en absoluto, y debe ser relativamente bajo procesamiento.

Por ejemplo:

Si tiene una clase de usuario, debería comprobar los parámetros de inicio de sesión/cierre de sesión entrantes, junto con las cookies, y asignarlos a variables de clase.

Si tiene una clase de base de datos, debe hacer la conexión a la base de datos para que esté lista cuando vaya a iniciar una consulta.

Si tienes una clase que se ocupa de un formulario en particular, debe ir a obtener los valores del formulario.

En muchas de mis clases, busco ciertos parámetros para definir una 'acción', como agregar, editar o eliminar.

Todas estas cosas no afectan realmente a la página, por lo que no importaría demasiado si las creaste o no. Simplemente están listos para cuando se va a llamar a ese primer método.

 0
Author: Tyler Carter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:31:24

No haría el análisis en el constructor. Yo haría todo lo necesario para validar los parámetros del constructor, y para asegurar que el HTML pueda ser analizado cuando sea necesario.

Pero tendría los métodos de acceso hacer el análisis si el HTML no se analiza en el momento en que necesitan que sea. El análisis puede esperar hasta ese momento - no es necesario hacerlo en el constructor.


Código sugerido, para propósitos de discusión:

public class MyHtmlScraper {
    private TextReader _htmlFileReader;
    private bool _parsed;

    public MyHtmlScraper(string htmlFilePath) {
        _htmlFileReader = new StreamReader(htmlFilePath);
        // If done in the constructor, DoTheParse would be called here
    }

    private string _parsedValue1;
    public string Accessor1 {
        get {
            EnsureParsed();
            return _parsedValue1;
        }
    }

    private string _parsedValue2;
    public string Accessor2 {
        get {
            EnsureParsed();
            return _parsedValue2;
        }
    }

    private void EnsureParsed(){
        if (_parsed) return;
        DoTheParse();
        _parsed = true;
    }

    private void DoTheParse() {
        // parse the file here, using _htmlFileReader
        // parse into _parsedValue1, 2, etc.
    }
}

Con este código en frente a nosotros, podemos ver que hay muy poca diferencia entre hacer todo el análisis en el constructor y hacerlo bajo demanda. Hay una prueba de una bandera booleana, y la configuración de la bandera, y las llamadas adicionales a EnsureParsed en cada accesor. Me sorprendería si ese código adicional no estaban alineadas.

Esto no es un gran problema, pero mi inclinación es hacer lo menos posible en el constructor. Eso permite escenarios donde la construcción necesita ser rápida. Estos sin duda serán situaciones que no has considerado, como la deserialización.

De nuevo, no es un gran problema, pero puede evitar hacer el trabajo en el constructor, y no es costoso hacer el trabajo en otro lugar. Admito, no es como si estuvieras haciendo E / S de red en el constructor (a menos, por supuesto, que se pase una ruta de archivo UNC), y no vas a tener que esperar mucho tiempo en el constructor (a menos que haya problemas de red, o generalices la clase para poder leer el HTML desde lugares distintos de un archivo, algunos de los cuales pueden ser lentos).

Pero como no tienes que hacerlo en el constructor, mi consejo es simplemente-no lo hagas.

Y si lo hace, podrían pasar años antes de que cause un problema, si es que lo hace.

 0
Author: John Saunders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 02:48:30

¿Por qué no simplemente pasar el analizador al constructor? Esto le permitiría cambiar la implementación sin cambiar el modelo:

public interface IParser
{
    Dictionary<string, object> ParseDocument(string document);
}

public class HtmlParser : IParser
{
    // Properties, etc...

    public Dictionary<string, object> ParseDocument(string document){
         //Do what you need to, return the collection of properties
         return someDictionaryOfHtmlObjects;
    }
}

public class HtmlScrapper
{
    // Properties, etc...

    public HtmlScrapper(IParser parser, string HtmlDocument){
         //Set your properties
    }

    public void ParseDocument(){
         this.myDictionaryOfHtmlObjects = 
                  parser.ParseDocument(this.htmlDocument);
    }

}

Esto debería darle cierta flexibilidad para cambiar/mejorar el rendimiento de su aplicación sin necesidad de reescribir esta clase.

 0
Author: Richard Clayton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 03:28:42

En mi caso, todo el contenido de la Los archivos HTML se pasan a través de una cadena. La cadena ya no es necesaria una vez se analiza y es bastante grande (a unos cientos de kilobytes). Así que sería mejor no guardarlo en la memoria. El objeto no debe ser utilizado para otros caso. Fue diseñado para analizar un cierta página. Analizar otra cosa debe impulsar la creación de un objeto diferente para analizar eso.

Suena como si tu objeto no fuera realmente un analizador. ¿Simplemente envuelve una llamada a un analizador y presenta los resultados de una manera (presumiblemente) más utilizable? Debido a esto, necesita llamar al analizador en el constructor ya que su objeto estaría en un estado no útil de lo contrario.

No estoy seguro de cómo la parte "orientada a objetos" ayuda aquí. Si solo hay un objeto y solo puede procesar una página específica, entonces no está claro por qué necesita ser un objeto. Usted podría hacer esto con la misma facilidad en procedimiento (es decir, no-OO) codificar.

Para lenguajes que solo tienen objetos (por ejemplo, Java), puede crear un método static en una clase que no tenga un constructor accesible y luego invocar el analizador y devolver todos los valores analizados en una Map o colección similar

 0
Author: barrowc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 03:42:01

Una posible opción es mover el código de análisis a una función separada, hacer que el constructor sea privado, y tener una función estática parse( html ) que construye el objeto e inmediatamente llama a la función parse.
De esta manera se evitan los problemas con el análisis en el constructur (estado inconsistente, problemas al llamar a funciones anuladas, ...). Pero el código del cliente todavía obtiene todas las ventajas (una llamada para obtener el html analizado o un error 'temprano').

 0
Author: jos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 06:46:50

Como muchos han comentado, la regla general es hacer solo inicialización en constructores y nunca usar, por ejemplo, métodos virtuales (obtendrá una advertencia del compilador si intenta prestar atención a esa advertencia :) ). En tu caso específico tampoco iría por el método parHTML. un objeto debe estar en un estado válido cuando se construye debe tener que hacer cosas al objeto antes de que realmente pueda usarlo.

Personalmente me gustaría ir por un método de fábrica. Exponer una clase sin público constructores y crearlo utilizando un método de fábrica en su lugar. Deja que tu método factory haga el análisis y pase el resultado analizado a un constructor privado / protegido.

Echa un vistazo al Sistema.Web.WebRequest si quieres ver una muestra de alguna lógica similar.

 0
Author: Rune FS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 09:53:30

Estoy de acuerdo con los posters aquí argumentando un trabajo mínimo en el constructor, realmente solo poniendo el objeto en un estado no zombi, luego tener funciones verbales como parseHTML ();

Un punto que me gustaría hacer, aunque no quiero causar una guerra de llamas, es considerar el caso de un entorno sin excepción. Sé que estás hablando de C#, pero trato de mantener mis modelos de programación lo más similares posible entre c++ y c#. Por varias razones, no uso excepciones en C++ (creo que incrustado programación de videojuegos), uso errores de código de retorno.

En este caso, no puedo lanzar excepciones en un constructor, por lo que tiendo a no hacer que un constructor haga nada que pueda fallar. Dejo eso a las funciones de los accesorios.

 0
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 11:26:58

En general, un constructor debe:

  1. Inicializa todos los campos.
  2. Deje el objeto resultante en un estado válido.

Sin embargo, no usaría el constructor de la manera que usted lo ha hecho. El análisis debe estar separado del uso de los resultados de análisis.

Generalmente cuando escribo un analizador lo escribo como un singleton. no almacena ningún campo en el objeto excepto la instancia única; en su lugar, solo uso variables locales dentro de los métodos. Teóricamente, estos podrían ser métodos estáticos (a nivel de clase), pero eso significaría que no podría hacerlos virtuales.

 0
Author: Imagist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-29 05:33:17

Personalmente no pongo nada en los constructores y tengo un conjunto de funciones de inicialización. Encuentro que los métodos de constructor estándar tienen una reutilización limitada y engorrosa.

 -1
Author: clemahieu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 03:42:48