Java 继承设计模式的不变性

Java 继承设计模式的不变性,java,scala,design-patterns,immutability,Java,Scala,Design Patterns,Immutability,我正在用Scala实现一些代码,遵循Java教程 本教程中有一段代码,可以最小化为以下内容: public abstract class A { private int id; public A(String name) { id = Helper.getId(name); fetchAllAttributes(); } protected abstract void fetchAllAttributes(); pro

我正在用Scala实现一些代码,遵循Java教程

本教程中有一段代码,可以最小化为以下内容:

public abstract class A {
    private int id;

    public A(String name) {
        id = Helper.getId(name);
        fetchAllAttributes();
    }

    protected abstract void fetchAllAttributes();

    protected int fetchAttribute(String attribute) {
        Helper.getAttribute(id, attribute);
    }

    public class B extends A {
        int volume;

        public B() {
            super("B");
        }

        @Override
        protected void fetchAllAttributes() {
            volume = super.fetchAttribute("volume");
        }

    }
}
这就是将其转换为Scala时的样子:

abstract class A(val name: String) {
  private val id = Helper.getId(name)
  fetchAllAttributes()

  protected def fetchAllAttributes(): Unit

  protected def fetchAttribute(attribute: String): Int = {
    Helper.getAttribute(id, attribute)
  }

  class B() extends A("B") {
    var volume = 0

    override protected def fetchAllAttributes(): Unit = {
      volume = super.fetchAttribute("volume")
    }
  }

}
这里我想问两个问题:

  • 这个模式是否有一个名称,在这个模式中,您在抽象类的构造函数中调用一个抽象方法,并提供一个方法供子类在其实现中使用
  • 作为Scala开发人员,我真的不喜欢可变对象和变量。是否有一种好方法可以以不变的方式实现这一点,只使用
    val
    s

  • 我不知道这个图案的名字。在不知道模式的目标的情况下,很难准确地知道如何将其转换为不变的样式,但如果你足够努力地眯着眼睛,这里有一些类似的东西:

    class FactoryFromAttributes[A](name: String) {
      def construct(f: (String => Int) => A): A = {
        val id = Helper.getId(name)
        f(str => Helper.getAttribute(id, str))
      }
    }
    
    class B(volume: Int)
    
    object B extends FactoryFromAttributes[B]("B") {
      def apply(): B = construct { fetchAttribute =>
        new B(fetchAttribute("volume"))
      }
    }
    
    对我来说,这种逻辑在伴生对象中更有意义,所以我将它移到了伴生对象中,而不是在生成的构造类中保留一个奇怪的子类关系。构造函数之外的初始化逻辑很少适合于良好的不可变样式

  • 你可以称之为反模式。请参见关于从构造函数调用可重写方法的说明
  • 当将java代码重构为scala代码时,在一开始对我帮助最大的是理解什么是有副作用的方法。您不希望在依赖可变字段的类中有方法和/或更改它们。(就像你的B类在该卷中所做的那样)这个小原则有助于保持类不处于可变状态。但这并不是一条一成不变的规则。例如,对于akka参与者来说,具有可变状态并不少见
  • 引用scala教程的一段话():

    同样,这意味着函数不应有任何副作用。它应该接受输入变量,而不是修改这些变量,然后计算并返回新的内容。与面向对象编程不同,您不应该更改(变异)其他变量的状态,即使这些变量是(a)类的变量或(b)传递给函数/方法的变量


    没有通用的方法将任何可变代码转换为不可变代码。您需要解释可变代码解决了什么问题,然后人们将能够帮助找到解决问题的不可变方法。从基类构造函数调用可重写方法(更不用说抽象方法)在Java中是一种反模式。子类的方法将在子类构造函数执行之前执行,这可能会导致各种问题。有关详细信息,请参阅。正确的处理方法是不公开任何公共构造函数,而是定义一个工厂方法,在对象完全构造后调用对象的
    fetchAllAttributes()
    方法。