首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >变异对象: Mutable<T>类

变异对象: Mutable<T>类
EN

Code Review用户
提问于 2015-11-17 23:59:53
回答 2查看 866关注 0票数 3

最近,我觉得需要编写一个Mutable<T>类,这样我就可以通过方法传递不可变的对象,然后可以更改这些方法的值。一些不可变类的示例(包括原始类型):

  • int
  • long
  • short
  • byte
  • double
  • float
  • String (虽然已经有了一个StringBuilder
  • BigInteger

还有其他的。

类中有大量的重复,特别是原语数类型。我肯定有办法避免重复,但我想不出怎么回事。

Mutable.java

很简单,对吧?

代码语言:javascript
复制
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;
    }

}

我还添加了一些额外的原语数字支持,以便:

代码语言:javascript
复制
Mutable<Integer> i = new Mutable<>(10);
i.setValue(i.getValue() + 10);

变成:

代码语言:javascript
复制
MutableInteger i = new MutableInteger(10);
i.add(10);

接口:

MutableNumber.java

代码语言:javascript
复制
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);

}

现在重复的部分:

MutableInteger.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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;
    }

}

关切事项:

  1. 有没有办法消除所有的重复?
  2. 我的班级结构好吗?

和往常一样,任何事情都是受欢迎的。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-11-18 01:31:46

您的代码是一个很好的例子,说明什么时候应该使用原语;-)严肃地说,您有一个与未定义类型的原始算术相关的问题。像+-这样的运算符是基于原语的(除了字符串级联),因此它们强烈地链接到特定的原语。代码是重复的,因为每个实现都有不同的原语组合。

在具有原始类型的其他语言中,如C或C++,您将遇到相同的问题,除非您也有无符号和有符号的变体,或者由于大量的转换而遭受其他问题。

公平地说,C++中的模板将有助于减少锅炉板,但语言本身将为您生成不同的代码实例。

那么,解决办法是什么?最好的解决方案是不封装原始操作。如果您需要执行1 + 1,那么就不要执行MutableInteger sum = new MutableInteger(1).add(1);

或者,为了减少样板,选择一个单独的数据类型,它是其他类型的超集,并使用它。在这种情况下,可能是BigDecimal.嗯,BigDecimal是一个Number,但是会导致代码失败.

使用BigDecimal,您可以使用BigDecimal算法实现所有主要方法,然后有一个受保护的方法将其转换回基础类.(如果无法进行回播,则抛出异常?)

代码语言:javascript
复制
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
EN

Code Review用户

发布于 2015-11-18 05:05:02

最近,我觉得需要编写一个可变的类,这样我就可以通过方法传递不可变的对象,然后可以更改这些方法的值。不可变类的一些示例(包括原语类型)

你的语言很混乱。我认为,您想要说的是,您感到需要编写一个Handle<T>类,这样您就可以对方法进行value objects,并能够在调用者中观察对这些值的更改。

(识别值对象的松散启发式:对对象执行操作将为您提供一个新的对象实例。)

代码语言:javascript
复制
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);
}

我确信Bertrand会告诉您这是一种代码气味;您的方法名称是在宣传方法改变了对象的状态并返回一个值。这不一定是错误的,但它暗示你应该重新审视你是否有正确的解决方案;这有时意味着重新审视你是否有正确的问题。

代码语言:javascript
复制
public Float sustractAndGet(Float number) {
    value -= number;
    return value;
}

如果你要用这种方法,它真的应该照它说的去做:

代码语言:javascript
复制
public Float sustractAndGet(Float number) {
    subtract(number);
    return get();
}

但回到顶端去

我觉得有必要写一个可变的类。

您可能不应该--这强烈地表明,您要替换的代码目前编写得很糟糕。对象只应很少负责执行计算和协调计算。相反,您应该将第一个对象传递给第二个对象。这是Builder模式的核心--导演协调应该发生的事情,而Builder跟踪计算。

因此,您可能有一个Builder接口,如下所示:

代码语言:javascript
复制
public interface NumberBuilder<T extends Number> {
    void add(T number);
    void sustract(T number);
    void multiply(T number);
    void divide(T number);
}

但是,更有可能的是,界面本身应该更好地表达您真正想要实现的目标:

代码语言:javascript
复制
public interface AccountBuilder<T extends Number> {
    void credit(T amount);
    void debit(T amount);
    void accrueInterest(T rate);
    // ...
}
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/111065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档