Diseño de constructores
Los constructores son métodos especiales utilizados para inicializar los tipos y crear instancias de tipos. Los constructores de tipo se utilizan para inicializar los datos estáticos en un tipo. Common Language Runtime (CLR) llama a un constructor de tipo antes de crear ninguna instancia del tipo. Los constructores de tipos son static (Shared en Visual Basic) y no pueden tomar parámetros. Para crear instancias de un tipo se utilizan constructores de instancia. Los constructores de instancias pueden tomar parámetros, pero no se les exige que lo hagan. Un constructor de instancia sin parámetros se denomina constructor predeterminado.
Las instrucciones siguientes describen los procedimientos recomendados para crear constructores.
Plantéese proporcionar constructores sencillos, idealmente predeterminados. Un constructor sencillo tiene un número muy pequeño de parámetros y todos los parámetros son tipos primitivos o enumeraciones.
Considere utilizar un método de generación estático en lugar de un constructor si la semántica de la operación deseada no se asignan directamente a la construcción de una nueva instancia, o si no parece natural seguir las instrucciones de diseño de constructores.
Utilice parámetros de constructor como accesos directos para establecer las propiedades principales.
Establecer las propiedades utilizando el constructor debería producir idénticos resultados que establecer directamente las propiedades. El ejemplo de código siguiente muestra una clase EmployeeRecord que se puede inicializar llamando a un constructor o estableciendo directamente las propiedades. La clase EmployeeManagerConstructor muestra cómo inicializar un objeto EmployeeRecord utilizando el constructor. La clase EmployeeManagerProperties muestra cómo inicializar un objeto EmployeeRecord mediante las propiedades. La clase Tester muestra esta posibilidad sin tener en cuenta la técnica utilizada, los objetos tienen el mismo estado.
Imports System
Imports System.Collections.ObjectModel
namespace Examples.DesignGuidelines.Constructors
' This Class can get its data either by setting
' properties or by passing the data to its constructor.
Public Class EmployeeRecord
private employeeIdValue as Integer
private departmentValue as Integer
Public Sub New()
End Sub
Public Sub New(id as Integer, department as Integer)
Me.employeeIdValue = id
Me.departmentValue = department
End Sub
Public Property Department as Integer
Get
Return departmentValue
End Get
Set
departmentValue = value
End Set
End Property
Public Property EmployeeId as Integer
Get
Return employeeIdValue
End Get
Set
employeeIdValue = value
End Set
End Property
Public Sub DisplayData()
Console.WriteLine("{0} {1}", EmployeeId, Department)
End Sub
End Class
' This Class creates Employee records by passing
' argumemnts to the constructor.
Public Class EmployeeManagerConstructor
Dim employees as Collection(Of EmployeeRecord) = _
new Collection(Of EmployeeRecord)()
Public Sub AddEmployee(employeeId as Integer, department as Integer)
Dim record as EmployeeRecord = new EmployeeRecord(employeeId, department)
employees.Add(record)
record.DisplayData()
End Sub
End Class
' This Class creates Employee records by setting properties.
Public Class EmployeeManagerProperties
Dim employees as Collection(Of EmployeeRecord)= _
new Collection(Of EmployeeRecord)()
Public Sub AddEmployee(employeeId as Integer, department as Integer)
Dim record as EmployeeRecord = new EmployeeRecord()
record.EmployeeId = employeeId
record.Department = department
employees.Add(record)
record.DisplayData()
End Sub
End Class
Public Class Tester
' The following method creates objects with the same state
' using the two different approaches.
Public Shared Sub Main()
Dim byConstructor as EmployeeManagerConstructor = _
new EmployeeManagerConstructor()
byConstructor.AddEmployee(102, 102)
Dim byProperties as EmployeeManagerProperties = _
new EmployeeManagerProperties()
byProperties.AddEmployee(102, 102)
End Sub
End Class
End Namespace
using System;
using System.Collections.ObjectModel;
namespace Examples.DesignGuidelines.Constructors
{
// This class can get its data either by setting
// properties or by passing the data to its constructor.
public class EmployeeRecord
{
private int employeeId;
private int department;
public EmployeeRecord()
{
}
public EmployeeRecord(int id, int department)
{
this.employeeId = id;
this.department = department;
}
public int Department
{
get {return department;}
set {department = value;}
}
public int EmployeeId
{
get {return employeeId;}
set {employeeId = value;}
}
public void DisplayData()
{
Console.WriteLine("{0} {1}", EmployeeId, Department);
}
}
// This class creates Employee records by passing
// argumemnts to the constructor.
public class EmployeeManagerConstructor
{
Collection<EmployeeRecord > employees = new Collection<EmployeeRecord>();
public void AddEmployee(int employeeId, int department)
{
EmployeeRecord record = new EmployeeRecord(employeeId, department);
employees.Add(record);
record.DisplayData();
}
}
// This class creates Employee records by setting properties.
public class EmployeeManagerProperties
{
Collection<EmployeeRecord > employees = new Collection<EmployeeRecord>();
public void AddEmployee(int employeeId, int department)
{
EmployeeRecord record = new EmployeeRecord();
record.EmployeeId = employeeId;
record.Department = department;
employees.Add(record);
record.DisplayData();
}
}
public class Tester
{
// The following method creates objects with the same state
// using the two different approaches.
public static void Main()
{
EmployeeManagerConstructor byConstructor =
new EmployeeManagerConstructor();
byConstructor.AddEmployee(102, 102);
EmployeeManagerProperties byProperties =
new EmployeeManagerProperties();
byProperties.AddEmployee(102, 102);
}
}
}
using namespace System;
using namespace System::Collections::ObjectModel;
namespace Examples { namespace DesignGuidelines { namespace Constructors
{
// This class can get its data either by setting
// properties or by passing the data to its constructor.
public ref class EmployeeRecord
{
private:
int employeeId;
int department;
public:
EmployeeRecord()
{
}
EmployeeRecord(int id, int department)
{
this->employeeId = id;
this->department = department;
}
property int Department
{
int get() {return department;}
void set(int value) {department = value;}
}
property int EmployeeId
{
int get() {return employeeId;}
void set(int value) {employeeId = value;}
}
void DisplayData()
{
Console::WriteLine("{0} {1}", EmployeeId, Department);
}
};
// This class creates Employee records by passing
// argumemnts to the constructor.
public ref class EmployeeManagerConstructor
{
private:
Collection<EmployeeRecord^>^ employees;
public:
EmployeeManagerConstructor()
{
employees = gcnew Collection<EmployeeRecord^>();
}
void AddEmployee(int employeeId, int department)
{
EmployeeRecord^ record = gcnew EmployeeRecord(employeeId, department);
employees->Add(record);
record->DisplayData();
}
};
// This class creates Employee records by setting properties.
public ref class EmployeeManagerProperties
{
private:
Collection<EmployeeRecord^>^ employees;
public:
EmployeeManagerProperties()
{
employees = gcnew Collection<EmployeeRecord^>();
}
void AddEmployee(int employeeId, int department)
{
EmployeeRecord^ record = gcnew EmployeeRecord();
record->EmployeeId = employeeId;
record->Department = department;
employees->Add(record);
record->DisplayData();
}
};
public ref class Tester
{
// The following method creates objects with the same state
// using the two different approaches.
public:
static void Main()
{
EmployeeManagerConstructor^ byConstructor =
gcnew EmployeeManagerConstructor();
byConstructor->AddEmployee(102, 102);
EmployeeManagerProperties^ byProperties =
gcnew EmployeeManagerProperties();
byProperties->AddEmployee(102, 102);
}
};
}}}
Tenga en cuenta que en estos ejemplos, y en una biblioteca bien diseñada, ambos enfoques crean los objetos en el mismo estado. No importa el enfoque que prefieran utilizar los desarrolladores.
Utilice el mismo nombre para los parámetros de constructor y una propiedad, si los parámetros de constructor se utilizan simplemente para establecer la propiedad. La única diferencia entre tales parámetros y las propiedades debería ser la grafía.
Esta instrucción se muestra en el ejemplo anterior.
Haga el trabajo mínimo en el constructor. Los constructores no deberían hacer muchos otros trabajos que captar los parámetros de constructor. El costo de cualquier otro procesamiento se debería retrasar hasta que fuera necesario.
Inicie las excepciones desde constructores de instancias si es adecuado.
Los constructores deberían iniciar y controlar las excepciones al igual que cualquier método. Específicamente, un constructor no debería detectar y ocultar ninguna excepción que no pueda controlar. Para obtener información adicional sobre las excepciones, vea Instrucciones de diseño de excepciones.
Declare explícitamente el constructor predeterminado público en clases, si se requiere este tipo de constructor.
Definir un constructor predeterminado es un procedimiento recomendado si su clase lo admite. Aun cuando algunos compiladores agregan automáticamente un constructor predeterminado a su clase, agregarlo explícitamente facilita el mantenimiento de código. También garantiza que el constructor predeterminado permanece definido aun cuando el compilador deje de emitirlo porque se agregue un constructor que toma parámetros.
Evite tener constructores predeterminados en estructuras.
Muchos compiladores, incluido el compilador de C#, no admiten constructores sin parámetros en estructuras.
No llame a miembros virtuales en un objeto incluido dentro de sus constructores.
Llamar a un miembro virtual hace que se llame al reemplazo más derivado, independientemente de que se haya llamado al constructor del tipo que define el reemplazo más derivado. El siguiente ejemplo de código muestra este problema. Cuando se ejecuta el constructor de la clase base, llama al miembro de clase derivada, aunque no se haya llamado al constructor de clase derivado. Este ejemplo imprime BadBaseClass para mostrar que el constructor DerivedFromBad no ha actualizado el campo del estado.
Imports System
Namespace Examples.DesignGuidelines.MemberDesign
Public Class BadBaseClass
Protected state as String
Public Sub New()
state = "BadBaseClass"
SetState()
End Sub
Public Overridable Sub SetState()
End Sub
End Class
Public Class DerivedFromBad
Inherits BadBaseClass
Public Sub New()
state = "DerivedFromBad "
End Sub
Public Overrides Sub SetState()
Console.WriteLine(state)
End Sub
End Class
Public Class tester
Public Shared Sub Main()
Dim b as DerivedFromBad = new DerivedFromBad()
End Sub
End Class
End Namespace
using System;
namespace Examples.DesignGuidelines.MemberDesign
{
public class BadBaseClass
{
protected string state;
public BadBaseClass()
{
state = "BadBaseClass";
SetState();
}
public virtual void SetState()
{
}
}
public class DerivedFromBad : BadBaseClass
{
public DerivedFromBad()
{
state = "DerivedFromBad ";
}
public override void SetState()
{
Console.WriteLine(state);
}
}
public class tester
{
public static void Main()
{
DerivedFromBad b = new DerivedFromBad();
}
}
}
using namespace System;
namespace Examples { namespace DesignGuidelines { namespace MemberDesign
{
public ref class BadBaseClass
{
protected:
String^ state;
public:
BadBaseClass()
{
state = "BadBaseClass";
SetState();
}
virtual void SetState()
{
}
};
public ref class DerivedFromBad : public BadBaseClass
{
public:
DerivedFromBad()
{
state = "DerivedFromBad ";
}
virtual void SetState() override
{
Console::WriteLine(state);
}
};
public ref class tester
{
public:
static void Main()
{
DerivedFromBad^ b = gcnew DerivedFromBad();
}
};
}}}
Portions Copyright 2005 Microsoft Corporation. Reservados todos los derechos.
Portions Copyright Addison-Wesley Corporation. Reservados todos los derechos.
Para obtener más información sobre las directrices de diseño, consulte “las instrucciones de diseño de Framework: Convenciones, frases realizadas y modelos para libro de bibliotecas reutilizables de .NET” de Krzysztof Cwalina y Brad Abrams, publicados por Addison-Wesley, 2005.
Vea también
Conceptos
Diseño de constructores de tipos
Otros recursos
Instrucciones de diseño de miembros
Instrucciones de diseño para desarrollar bibliotecas de clases