mejor - java vs c# 2018
hacer esto sin usar un "si" | if(s== “value1”){…} else if(s== “value2”){…} (18)
Abusar del operador ternario, al menos en C #:
Action result =
s == "bar" ? (Action)(() => { Console.WriteLine("bar"); }):
s == "foo" ? (Action)(() => { Console.WriteLine("foo"); }) :
(Action)(() => { Console.WriteLine(); });
En realidad, lo retiro ... nunca NUNCA hago esto. Utilice un interruptor.
De acuerdo con la campaña anti-if , es una buena práctica no usar ifs en nuestro código. ¿Alguien puede decirme si es posible deshacerse del if en este código? (el interruptor tampoco es una opción, el punto es eliminar la lógica condicional, no reemplazar los ifs con construcciones de lenguaje similares )
if(s == "foo")
{
Writeln("some logic here");
}
else if(s == "bar")
{
Writeln("something else here");
}
else if(s == "raboof")
{
Writeln("of course I need more than just Writeln");
}
(Idioma: Java o C #)
Aquí hay una manera ... :)
delegate void DoStuff();
...
IDictionary<string, DoStuff> dict = new Dictionary<string, DoStuff>();
dict["foo"] = delegate { Console.WriteLine("some logic here"); };
dict["bar"] = delegate { Console.WriteLine("something else here"); };
dict["raboof"] = delegate { Console.WriteLine("of course I need more than just Writeln"); };
dict["foo"]();
Aquí va la mía. Usando LINQ y Factory Pattern: D
class FactoryString
{
static FactoryString()
{
private static Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{"foo", "some logic here"},
{"bar", "something else here"},
{"raboof", "of course I need more than just Writeln"},
};
}
public static string getString(string s)
{
return dictionary.Single(x => x.Key.Equals(s)).Value;
}
}
static void main()
{
Console.WriteLine(FactoryString.getString("foo"));
}
Creo que estás buscando patrones de fábrica .
El ejemplo que ha dado no cambiaría (aunque creo que se da cuenta de que no es necesario cambiarlo). Supongo que lo está utilizando como un ejemplo representativo.
En el libro de Refactorización de Fowler, él discute el Reemplazo Condicional con Polimorfismo. Eso es lo que considero un buen uso para reemplazar las declaraciones if / switch (cuando corresponda).
En algunos casos podría ser legítimo evitar la estructura if.
en otros es simplemente una idiotez tratar de evitar si.
Si bien los ejemplos proporcionados para evitar la estructura if son alternativas válidas, debe preguntarse esto:
¿Por qué estoy haciendo mi código innecesariamente complicado para evitar una estructura simple? Si la única razón es que tienes que hacerlo debido a la campaña anti-if, entonces es una mala razón.
En cuanto a la campaña, está muy mal explicado. No hay nada de malo en ifs, pero en ciertos casos pueden indicar que no está utilizando la POO en todo su potencial.
Lo que la campaña está tratando de promover es un mayor uso del polimorfismo para desacoplar el código de llamada del tipo de objeto que está mirando.
Usaría algún objeto más inteligente en lugar de que s sea una cadena:
interface I {
public String getName();
public void doSomething();
}
class A implements I {
public String getName() { return "one"; }
public void doSomething() { ...; }
}
class B implements I {
public String getName() { return "two"; }
public void doSomething() { ...; }
}
Entonces puedes reemplazar los ifs con:
I obj = ...get an A or B from somewhere...;
obj.doSomething();
En primer lugar, preste mucha atención al leer estas campañas "anti".
- Pregúntese si la campaña Anti-IF desea eliminar la lógica en las aplicaciones.
- Las ideas podrían tener una buena aplicación en una situación y una estupidez en otra . Sé razonable.
- Es posible que el uso múltiple de IF pueda afectar al lector del código. pero esta es una razón para eliminar el if de su código, más que esto, esto es casi imposible.
- A propósito, en cualquier parte de las directrices de diseño de MS se indica que no se usa si (como se hace, por ejemplo, no se recomienda el uso del goto enunciado) ...
DO#
switch (myStringVar)
{
case "one": doSomething(); break;
case "two": doSomething(); break;
case "three": doSomething(); break;
default: doSomething(); break;
}
Finalmente, reduce este código a la if s ... por lo tanto, solo para mejorar la legibilidad es mejor, no para el rendimiento.
En realidad, si Microsoft cree que es mejor reemplazar el interruptor (en c #) con if - OK, usaré (en la situación concreta que usted describió) el interruptor .
Por cierto, parece que la campaña responde a su pregunta muy clara en este ejemplo.
Es posible que pueda hacer algo similar al patrón de "estrategia" anterior usando un mapa de llamadas a métodos:
public class FooOrBar {
private Map<String, Method> methodMap = new HashMap<String, Method>();
public FooOrBar() {
try {
methodMap.put("foo", this.getClass().getMethod("doFoo", new Class[0]));
methodMap.put("bar", this.getClass().getMethod("doBar", new Class[0]));
} catch (NoSuchMethodException n) {
throw new RuntimeException(n);
}
}
public void doSomething(String str) {
Method m = methodMap.get(str);
try {
m.invoke(this, null);
} catch (Exception n) {
throw new RuntimeException(n);
}
}
public void doFoo() {
System.out.println("foo");
}
public void doBar() {
System.out.println("bar");
}
public static void main(String[] args) {
FooOrBar fb = new FooOrBar();
fb.doSomething("foo");
}
}
Hacer una estructura de datos asociativa. Map<String, String>
en Java, IDictionary<string, string>
en C #. Inicializarlo al principio del tiempo, y luego ...
Hacer uso del patrón de estrategia .
En términos de Java:
public interface Strategy {
void execute();
}
public class SomeStrategy implements Strategy {
public void execute() {
System.out.println("Some logic.");
}
}
que utiliza de la siguiente manera:
Map<String, Strategy> strategies = new HashMap<String, Strategy>();
strategies.put("strategyName1", new SomeStrategy1());
strategies.put("strategyName2", new SomeStrategy2());
strategies.put("strategyName3", new SomeStrategy3());
// ...
strategies.get(s).execute();
Leí http://www.antiifcampaign.com/articles/the-simplest-anti-if-code.html y creo que el medicamento es peor que la enfermedad. Mucho, mucho peor. Debes invertir por adelantado en alguna maquinaria pesada de OO para resolver un posible problema futuro (¿improbable?).
Me gustaría señalar que hasta ahora, cada respuesta a esta pregunta con un ejemplo de código tiene una solución mucho más complicada que el código original, y probablemente mucho más lenta.
Este es un caso clásico de una optimización que se realiza en un contexto totalmente incorrecto. en algunos casos, el código se volverá más claro mediante el uso correcto de OO, como la eliminación de largas cadenas de verificación de tipos. sin embargo, simplemente eliminar todas las declaraciones if para eliminarlas solo sirve para ofuscar su código.
Las declaraciones if (saltos condicionales) todavía van a suceder, ya sea en su código o en el intérprete. mantenerlos cerca léxicamente tiene muchas ventajas de legibilidad y mantenimiento que se pierden debido al uso excesivo de OO. hay un equilibrio que se debe encontrar entre la lógica local y la lógica distante, pero nunca debe extenderse a la ofuscación.
para la pregunta en cuestión, la construcción más clara que evitará el if
es probablemente una tabla hash / matriz asociativa que contiene funciones anónimas, que, para un pequeño número de claves, es en realidad solo una instrucción de cambio lento.
Mi perspectiva general sobre este tipo de problema no es que si las declaraciones son malas, es que es más fácil depurar los datos que depurar el código.
Aquí hay un ejemplo no trivial del código de producción. Esto puede parecer un poco complicado a primera vista, pero en su esencia es muy simple: dependiendo del código de disposición en una fila de carga, debemos realizar una actualización de algunas de las filas de oraciones relacionadas. Pero seleccionamos diferentes filas de oraciones y realizamos diferentes tipos de actualizaciones en ellas, para diferentes códigos de disposición.
Este es un ejemplo relativamente simple: solo hay cinco códigos de disposición, dos pruebas y dos tipos de actualizaciones. Aun así, esto es mucho más simple de lo que reemplazó. Además, es mucho más fácil decir simplemente al ver el código que hace lo que los requisitos dicen que debería hacer, ya que las asignaciones en el código corresponden a las tablas en el documento de requisitos. (Antes de escribir este código, tuve que volver a escribir el documento de requisitos para que todo se definiera en una tabla. El código original era un desastre porque los requisitos también eran un desastre. Reescribió los requisitos para hacerlos más claros en el requisitos, también.)
Vale la pena enfatizar que es bastante fácil escribir una prueba unitaria que cubra el 100% de este código. También vale la pena enfatizar que la complejidad de este código se escala linealmente con la cantidad de códigos de disposición, predicados y actualizaciones que admite; si se usara un caso o si se usaran sentencias, se escalaría exponencialmente.
/// <summary>
/// Update a sentence''s status to Completed [401110]
/// </summary>
/// <param name="senRow"></param>
/// <param name="eventDate"></param>
private static void CompleteSentence(DataRow senRow, DateTime eventDate)
{
senRow.SetField("SenStatus", "401110");
senRow.SetField("SenStatusDate", eventDate);
}
/// <summary>
/// Update a sentence''s status to Terminated [401120]
/// </summary>
/// <param name="senRow"></param>
/// <param name="eventDate"></param>
private static void TerminateSentence(DataRow senRow, DateTime eventDate)
{
senRow.SetField("SenStatus", "401120");
senRow.SetField("SenStatusDate", eventDate);
}
/// <summary>
/// Returns true if a sentence is a DEJ sentence.
/// </summary>
/// <param name="senRow"></param>
/// <returns></returns>
private static bool DEJSentence(DataRow senRow)
{
return Api.ParseCode(senRow.Field<string>("SenType")) == "431320";
}
/// <summary>
/// Returns true if a sentence is a Diversion sentence.
/// </summary>
/// <param name="senRow"></param>
/// <returns></returns>
private static bool DiversionSentence(DataRow senRow)
{
return Api.ParseCode(senRow.Field<string>("SenType")).StartsWith("43");
}
/// <summary>
/// These are predicates that test a sentence row to see if it should be updated
/// if it lives under a charge disposed with the specified disposition type.
///
/// For instance, if the PDDispositionCode is 413320, any DEJ sentence under the
/// charge should be updated.
/// </summary>
private static readonly Dictionary<string, Func<DataRow, bool>> PDSentenceTests =
new Dictionary<string, Func<DataRow, bool>>
{
{"411610", DiversionSentence}, // diversion successful
{"413320", DEJSentence}, // DEJ successful
{"442110", DiversionSentence}, // diversion unsuccessful
{"442111", DiversionSentence}, // diversion unsuccessful
{"442112", DiversionSentence}, // diversion unsuccessful
{"442120", DEJSentence} // DEJ unsuccessful
};
/// <summary>
/// These are the update actions that are applied to the sentence rows which pass the
/// sentence test for the specified disposition type.
///
/// For instance, if the PDDispositionCode is 442110, sentences that pass the sentence
/// test should be terminated.
/// </summary>
private static readonly Dictionary<string, Action<DataRow, DateTime>> PDSentenceUpdates =
new Dictionary<string, Action<DataRow, DateTime>>
{
{"411610", CompleteSentence}, // diversion successful (completed)
{"413320", CompleteSentence}, // DEJ successful (completed)
{"442110", TerminateSentence}, // diversion unsuccessful (terminated)
{"442111", TerminateSentence}, // diversion unsuccessful (terminated)
{"442112", TerminateSentence}, // diversion unsuccessful (terminated)
{"442120", TerminateSentence} // DEJ unsuccessful (terminated)
};
private void PDUpdateSentencesFromNewDisposition()
{
foreach (DataRow chargeRow in PDChargeRows
.Where(x => PDSentenceTests.ContainsKey(x.Field<string>("PDDispositionCode"))))
{
string disp = chargeRow.Field<string>("PDDispositionCode");
foreach (DataRow s in CHGRows[chargeRow]
.ChildRows("CAS-SUBCRM-CHG-SEN")
.Where(x => PDSentenceTests[disp](x)))
{
PDSentenceUpdates[disp](s, EventDate);
}
}
}
No creo que estés haciendo una comparación justa aquí.
Desde el punto de vista de la campaña Anti-if, solo se trata de practicar un mejor enfoque de diseño.
Sin embargo, en su caso, puede ver en todos los ejemplos anteriores que, si no pueden eliminarse de la superficie y siempre existirán en algún lugar en el centro.
¿Y por qué exactamente es eso?
Bueno, si es un propósito general de la vida. No quiero decir comenzar a codificar en todas partes, pero en general sin si no hay diferenciación, si aporta decisiones y propósito, si eso no existiera, entonces cada objeto en el mundo simplemente se ejecutaría como se supone, sin siquiera saberlo. Cualquier otra cosa que no sea yo mismo. Y muy simple no hubieras hecho esta pregunta. :)
Un poco tarde para la fiesta, pero combinando las respuestas del diccionario de C # de MRFerocius y share da la siguiente implementación de la share de share :
private Dictionary<string,Action> data = new Dictionary<string, Action> {
{"foo", () => Console.WriteLine("Some logic here")},
{"bar", () => Console.WriteLine("something else here")},
{"raboof", () => Console.WriteLine("of course I need more than just WriteLine")},
}
public static void main(String[] args) {
data["foo"]();
}
- Si la clave no existe en el diccionario, usarla en el indexador generará una excepción.
Se pueden componer múltiples acciones:
Puede haber múltiples llamadas a diferentes métodos, utilizando la sintaxis lambda multilínea:
{"foobar", () => { data["foo"](); data["bar"](); }
Como
Action
es un tipo de delegado, se pueden adjuntar múltiples métodos a una sola instancia de delegado y esa instancia de delegado se establece como el valor; se llamarán secuencialmente cuando se invoque al delegado:public static void main(String[] args) { data["foobar"] = data["foo"] + data["bar"]; //This will invoke first data["foo"] then data["bar"] data["foobar"](); }
Para los métodos a los que no se hace referencia a través del diccionario, esto también se puede hacer en el inicializador de la colección:
{"foobar", (Action)method1 + method2}
escriba clases con métodos virtuales que se deriven de su clase base abstracta SomeThingWriter.
Entonces, cada clase que se derive de la clase base debe implementar una función como writeSomething o lo que quieras.
abstract class MyBaseClass
{
public abstract void writeSomething();
}
class DerivedClass1 : MyBaseClass
{
public override void writeSomething()
{
Writeln("something else here 1");
}
}
class DerivedClass2 : MyBaseClass
{
public override void writeSomething()
{
Writeln("something else here 2");
}
}
que simplemente llamar como
MyBaseClass c = new DeriveClass1();
c.writeSomething();
c = new DerivedClass2();
c.writeSomething();
Java
Utilice una enumeración que implementa un determinado método.
enum MyEnum{
foo{
public void mymethod(String param1, String param2){
//dostuff...
}
},
bar{
public void mymethod(String param1, String param2){
//dostuff...
}
};
public abstract void mymethod(String param1, String param2);
}
Luego en tu clase:
MyEnum.valueOf(mystring).mymethod(param1, param2);