Objetos Mutando: Clase <T> MUTables -- java campo con generics camp codereview Relacionados El problema

Mutating Objects: Mutable<T> class


3
vote

problema

Español

Recientemente sentí la necesidad de escribir una clase 9988776665544330 para que pueda pasar objetos inmutables a través de métodos, cuyo valor se puede cambiar. Algunos ejemplos de clases inmutables (incluidos los tipos primitivos):

  • int
  • long
  • short
  • byte
  • double
  • float
  • String (Aunque ya tiene un 99887776655443388 clase
  • BigInteger

y otros.

Hay mucha repetición en las clases, especialmente los tipos de números primitivos. Estoy seguro de que hay un camino alrededor de la repetición, pero no pude averiguar cómo.

mutable.java

es bastante simple, ¿verdad?

  int0  

También agregué un poco de soporte de números primitivos adicionales, de modo que:

  int1  

se convierte en:

  int2  

La interfaz:

mutabledenumber.java

  int3  

Ahora la parte repetitiva:

mutableinteger.java

  int4  

mutablelong.java

  int5  

mutableuble.java

  int6  

mutablefloat.java

  int7  

Preocupaciones:

  1. ¿Hay alguna manera de eliminar toda la repetición?
  2. es mi estructura de clase buena?

y como de costumbre, cualquier otra cosa es bienvenida.

Original en ingles

Recently I felt the need to write a Mutable<T> class so that I can pass immutable objects through methods, whose value can then be changed. Some examples of immutable classes (including primitive types):

  • int
  • long
  • short
  • byte
  • double
  • float
  • String (though already has a StringBuilder class
  • BigInteger

and others.

There is a lot of repetition in the classes, especially the primitive number types. I am sure there is a way around the repetition, but I couldn't figure out how.

Mutable.java

It's quite simple, right?

public class Mutable<T> {      protected T value;      public Mutable(T value) {         setValue(value);     }      public T getValue() {         return value;     }      public void setValue(T value) {         this.value = value;     }  } 

I also added some extra primitive number support, so that:

Mutable<Integer> i = new Mutable<>(10); i.setValue(i.getValue() + 10); 

becomes:

MutableInteger i = new MutableInteger(10); i.add(10); 

The interface:

MutableNumber.java

public interface MutableNumber<T extends Number> {      public abstract void add(T number);      public abstract T addAndGet(T number);      public abstract void sustract(T number);      public abstract T sustractAndGet(T number);      public abstract void multiply(T number);      public abstract T multiplyAndGet(T number);      public abstract void divide(T number);      public abstract T divideAndGet(T number);  } 

Now the repetitive part:

MutableInteger.java

public class MutableInteger extends Mutable<Integer> implements         MutableNumber<Integer> {      public MutableInteger(Integer value) {         super(value);     }      public void increment() {         value++;     }      public int incrementAndGet() {         return ++value;     }      public void decrement() {         value--;     }      public int decrementAndGet() {         return --value;     }      @Override     public void add(Integer number) {         value += number;     }      @Override     public Integer addAndGet(Integer number) {         value += number;         return value;     }      @Override     public void sustract(Integer number) {         value -= number;     }      @Override     public Integer sustractAndGet(Integer number) {         value -= number;         return value;     }      @Override     public void multiply(Integer number) {         value *= number;     }      @Override     public Integer multiplyAndGet(Integer number) {         value *= number;         return value;     }      @Override     public void divide(Integer number) {         value /= number;     }      @Override     public Integer divideAndGet(Integer number) {         value /= number;         return value;     }  } 

MutableLong.java

public class MutableLong extends Mutable<Long> implements MutableNumber<Long> {      public MutableLong(Long value) {         super(value);     }      @Override     public void add(Long number) {         value += number;     }      @Override     public Long addAndGet(Long number) {         value += number;         return value;     }      @Override     public void sustract(Long number) {         value -= number;     }      @Override     public Long sustractAndGet(Long number) {         value -= number;         return value;     }      @Override     public void multiply(Long number) {         value *= number;     }      @Override     public Long multiplyAndGet(Long number) {         value *= number;         return value;     }      @Override     public void divide(Long number) {         value /= number;     }      @Override     public Long divideAndGet(Long number) {         value /= number;         return value;     }  } 

MutableDouble.java

public class MutableDouble extends Mutable<Double> implements         MutableNumber<Double> {      public MutableDouble(Double value) {         super(value);     }      @Override     public void add(Double number) {         value += number;     }      @Override     public Double addAndGet(Double number) {         value += number;         return value;     }      @Override     public void sustract(Double number) {         value -= number;     }      @Override     public Double sustractAndGet(Double number) {         value -= number;         return value;     }      @Override     public void multiply(Double number) {         value *= number;     }      @Override     public Double multiplyAndGet(Double number) {         value *= number;         return value;     }      @Override     public void divide(Double number) {         value /= number;     }      @Override     public Double divideAndGet(Double number) {         value /= number;         return value;     }  } 

MutableFloat.java

public class MutableFloat extends Mutable<Float> implements         MutableNumber<Float> {      public MutableFloat(Float value) {         super(value);     }      @Override     public void add(Float number) {         value += number;     }      @Override     public Float addAndGet(Float number) {         value += number;         return value;     }      @Override     public void sustract(Float number) {         value -= number;     }      @Override     public Float sustractAndGet(Float number) {         value -= number;         return value;     }      @Override     public void multiply(Float number) {         value *= number;     }      @Override     public Float multiplyAndGet(Float number) {         value *= number;         return value;     }      @Override     public void divide(Float number) {         value /= number;     }      @Override     public Float divideAndGet(Float number) {         value /= number;         return value;     }  } 

Concerns:

  1. Is there a way to remove all the repetition?
  2. Is my class structure good?

And as usual, anything else is welcome.

     
       
       

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 

Su código es un gran ejemplo de cuándo se adhiere a los primitivos ;-) En serio, sin embargo, en serio, lo que tiene, existe un problema relacionado con la aritmética primitiva en tipos indefinidos. Los operadores como + y - se basan en la primitiva (excepto la concatenación de cadena) y, como resultado, están fuertemente vinculados a primitivos específicos. El código se repite porque cada implementación tiene una combinación diferente de primitivas.

En otros idiomas con tipos primitivos, como C, o C ++, tendría el mismo tipo de problemas, excepto que también tendría variantes sin firmar y firmado con variantes, o, por lo demás, sufrirían grandes cantidades de fundición.

En equidad, las plantillas en C ++ ayudarán a reducir la placa de caldera, pero el idioma en sí generará diferentes instancias del código para usted.

Entonces, ¿cuál es la solución? Bueno, la mejor solución es no encapsular las operaciones primitivas. Si necesita hacer 1 + 1 , luego haga eso, no haga 9988776655544333 .

Alternativamente, para reducir la placa de caldera, seleccione un solo tipo de datos que sea un superset de los otros tipos y use eso. En este caso, probablemente BigDecimal ..... hmmm, 9988776655544335 es un 9988776655544336 , pero hará que su código falle ...

con BigDecimal , puede implementar todos sus métodos principales usando BigDecimal aritmético, y luego tiene un solo método protegido para traducirlo de nuevo a la clase subyacente ... (¿Y tirar una excepción si el retroceso no es posible?)

  public abstract Mutable<T extends Number> {     protected abstract T backCast(BigDecimal result);     protected abstract BigDecimal getDecimal();      public T add(T number) {         return backCast(getDecimal().add(BigDecimal.valueOf(number.toString()));     }      .....  }   
 

Your code is a great example of when to stick with primitives ;-) Seriously, though, what you have there is a problem related to primitive arithmetic on undefined types. Operators like + and - are primitive-based (except for string concatenation) and as a result they are strongly linked to specific primitives. The code is repeated because each implementation has a different combination of primitives.

In other languages with primitive types, like C, or C++ you would have the same sorts of problems, except you would have unsigned and signed variants as well, or otherwise suffer with large amounts of casting.

In fairness, templates in C++ will help reduce the boiler-plate, but the language itself will generate different instances of the code for you.

So, what's the solution? Well, the best solution is to not encapsulate primitive operations. If you need to do 1 + 1, then do that, don't do MutableInteger sum = new MutableInteger(1).add(1);.

Alternatively, to reduce boilerplate, select a single datatype that is a superset of the other types, and use that. In this case, probably BigDecimal..... hmmm, BigDecimal is a Number, but will cause your code to fail....

With BigDecimal, you can implement all your major methods using BigDecimal arithmetic, and then have a single protected method to translate it back to the underlying class.... (and throw an exception if the back-cast is not possible?)

public abstract Mutable<T extends Number> {     protected abstract T backCast(BigDecimal result);     protected abstract BigDecimal getDecimal();      public T add(T number) {         return backCast(getDecimal().add(BigDecimal.valueOf(number.toString()));     }      .....  } 
 
 
4
 
vote

Recientemente sentí la necesidad de escribir una clase mutable para que pueda pasar objetos inmutables a través de métodos, cuyo valor se puede cambiar. Algunos ejemplos de clases inmutables (incluidos los tipos primitivos)

Su idioma es confuso. Lo que quiere decir, creo que es que está sintiendo la necesidad de escribir una clase 998877666554433310 para que pueda 99887766555443311 a los métodos, y poder observar los cambios a esos valores en la persona que llama.

(heurístico suelto para identificar objetos de valor: realizar una operación en el objeto le da una nueva instancia de objeto).

  -2  

Estoy bastante seguro de que Bertrand Meyer le diría que es un código de código allí; Los nombres de sus métodos son publicitarios que los métodos cambian el estado del objeto y devuelven un valor. No está necesariamente incorrecto, pero es una pista que debe volver a examinar si tiene la solución correcta; que a veces significa volver a examinar si tiene el problema del derecho

  -3  

Si usted es que va a tener ese método, realmente debería hacer lo que dice en la lata:

  -4  

pero volver a la parte superior

Sentí la necesidad de escribir una clase mutable

Probablemente no debería tenerlo, sugiere firmemente que el código que tiene la intención de reemplazar está actualmente escrito. Los objetos deben ser muy raramente responsables de la realización de cálculos y coordinando los cálculos. En su lugar, debe pasar el primer objeto al segundo. Este es el núcleo del patrón de constructor: el director coordina lo que debería suceder, y el constructor rastrea el cálculo.

Para que pueda tener una interfaz 99887766555443315 que parece:

  -6  

Pero es más probable que la interfaz en sí sea más expresiva de lo que realmente está tratando de lograr:

  -7  
 

Recently I felt the need to write a Mutable class so that I can pass immutable objects through methods, whose value can then be changed. Some examples of immutable classes (including primitive types)

Your language is confusing. What you mean to say, I think, is that you are feeling the need to write a Handle<T> class so that you can value objects to methods, and be able to observe the changes to those values in the caller.

(Loose heuristic for identifying value objects: performing an operation on the object gives you a new object instance.)

public interface MutableNumber<T extends Number> {     public abstract T addAndGet(T number);     public abstract T sustractAndGet(T number);     public abstract T multiplyAndGet(T number);     public abstract T divideAndGet(T number); } 

I'm pretty sure Bertrand Meyer would tell you that's a code smell there; your method names are advertising that the methods change the state of the object and return a value. It's not necessarily wrong -- but it's a hint that you should be re-examining whether you have the right solution; which sometimes means re-examining whether you have the right problem

public Float sustractAndGet(Float number) {     value -= number;     return value; } 

If you are going to have that method, it really should do what it says on the tin:

public Float sustractAndGet(Float number) {     subtract(number);     return get(); } 

But going back to the top

I felt the need to write a Mutable class

You probably shouldn't have -- it strongly suggests that the code you intend to replace is currently badly written. Objects should only very rarely be responsible for both carrying out calculations and coordinating the calculations. Instead, you should pass the first object to the second. This is the core of the Builder pattern -- the Director coordinates what should happen, and the Builder tracks the calculation.

So you might have a Builder interface that looks like:

public interface NumberBuilder<T extends Number> {     void add(T number);     void sustract(T number);     void multiply(T number);     void divide(T number); } 

But it's more likely that the interface itself should be more expressive of what you are really trying to achieve:

public interface AccountBuilder<T extends Number> {     void credit(T amount);     void debit(T amount);     void accrueInterest(T rate);     // ... } 
 
 

Relacionados problema

2  Organización de código de deserialización de estructura variante  ( Variant structure deserialization code organization ) 
En mi proyecto, trabajo con objeto COM a través de Questions8 . Com Objeto Devoluciones Puntero en Estructura Questions9 , que eché como Sections0 y luego...

7  Clase de valor almacenado en caché genérico imitando perezosos <t>  ( Generic cached value class mimicking lazyt ) 
Antes de escribir esto, busqué y encontré una serie de soluciones que hacen uso de un proveedor de almacenamiento en caché para manejar un conjunto de artícul...

7  Implementar una secuencia de Fibonacci genérica en óxido sin usar copia rasgo  ( Implement a generic fibonacci sequence in rust without using copy trait ) 
Estoy tratando de aprender a óxido y soy un principiante. ¿Cómo se hace frente a la implementación de una versión genérica de la secuencia FIBONACCI sin usar ...

4  Implementación de Singleton usando genéricos  ( Singleton implementation using generics ) 
Hice esto como un ejercicio solo para practicar / mejorar el uso de genéricos. Independiente de lo útil que es esta implementación de un singleton, ¿cómo es...

7  Array Genérico  ( Generic arraylist ) 
¿Puede alguien recomendar mejoras al método de compresa ()? public class ArrayList<E> { private Object[] array; public static final int DEFAULT_SIZE = 20...

8  Aplanamiento recursivo de secuencias rápidas  ( Recursive flattening of swift sequences ) 
en aplanar Obtenga todos los controles infantiles de cierto tipo en una UIVIE , se discutieron los métodos para Recursivamente aplanar una estructura similar...

1  Java Gennics, convertir la lista anidada a la matriz  ( Java generics convert nested list to array ) 
Tengo que interactuar con un código antiguo usando matrices anidadas, por lo que tengo que convertir mis listas anidadas a las matrices anidadas. Cualquier id...

1  Función de aplanamiento de la matriz genérica  ( Generic array flattening function ) 
Con la ayuda de la comunidad de CodereView, he escrito una función para aplanar una matriz anidada genérica. Lo tengo escrito de varias maneras, pero quiere c...

3  Genéricos anulables - implementando secuencialSearchst en C #  ( Nullable generics implementing sequentialsearchst in c ) 
Para fines de aprendizaje, estoy implementando cierto código de SEDEDWICK & AMP; Los algoritmos de Wayne, cuarta edición . Debido a las características del...

1  Implementación rápida equivalente a colecciones  ( Quicksort implementation equivalent to collections sort ) 
Aquí está mi ir a comprender genéricos, 99887776655443312 S y for3 S, así como en los límites de tipo. Creo que lo hice tan cerca de for4 como sea posib...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos