Cuando creo una aplicación, normalmente creo una clase estática que contiene métodos y propiedades estáticas que no puedo encontrar en otro sitio.
No es un diseño especialmente bueno, pero ese es el punto: me da un lugar para localizar toda una clase de decisiones de diseño que aún no he pensado. En general, a medida que la aplicación crece y se perfecciona a través de la refactorización, se vuelve más claro dónde deberían residir realmente estos métodos y propiedades. Afortunadamente, el estado de las herramientas de refactorización es tal que esos cambios generalmente no son excepcionalmente dolorosos de realizar.
He intentado hacerlo de otra forma, pero a la inversa está implementando un modelo de objetos antes de saber lo suficiente sobre mi aplicación para diseñar el modelo de objetos correctamente. Si hago que, gasto una buena cantidad de tiempo y energía con una solución mediocre que tengo que revisar y reconstruir desde cero en algún momento en el futuro. Bien, está bien, si sé que voy a refaccionar este código, ¿qué tal si me salte el paso de diseñar y construir las clases innecesariamente complicadas que realmente no funcionan?
Por ejemplo, he creado una aplicación que está siendo utilizada por varios clientes. Descubrí desde el principio que necesitaba una forma de separar los métodos que deben funcionar de forma diferente para diferentes clientes. Creé un método de utilidad estático al que podía llamar en cualquier punto del programa donde necesitaba llamar a un método personalizado, y lo atrapé en mi clase estática.
Esto funcionó bien durante meses. Pero llegó un momento en que empezaba a parecer feo. Y entonces decidí refactorizarlo en su propia clase.Y mientras revisaba mi código mirando todos los lugares donde se llamaba este método, quedó muy claro que todos los métodos personalizados realmente necesitaban ser miembros de una clase abstracta, los ensamblajes de los clientes debían contener una única clase derivada que implementa todos los métodos abstractos, y luego el programa solo necesitaba sacar el nombre del ensamblaje y el espacio de nombres de su configuración y crear una instancia de la clase de características personalizadas al inicio. Fue muy sencillo para mí encontrar todos los métodos que tenían que personalizarse, ya que todo lo que tenía que hacer era encontrar todos los lugares donde se llamaba a mi método de cargar una característica personalizada. Me llevó casi toda la tarde recorrer toda la base de código y racionalizar este diseño, y el resultado final es realmente flexible y robusto y resuelve el problema correcto.
La cuestión es que cuando implementé ese método por primera vez (en realidad eran tres o cuatro métodos interrelacionados), reconocí que no era la respuesta correcta. Pero no sabía lo suficiente como para decidir cuál era la respuesta correcta. Así que fui con la respuesta incorrecta más simple hasta que la respuesta correcta fue clara.
La pregunta es sobre C#, no sobre Java. De todos modos, la clase String está sellada (final en Java), tanto en .NET como en Java –