有没有办法将类实例中的变量的更改传播到从其派生的其他类实例?

时间:2017-04-18 00:10:45

标签: java class object inheritance composition

问题:我想要实现的是让Parent类的实例将其局部变量的更改传播到直接从{{Child派生的Parent类实例1}}。我目前的方法是extend Parent类到Child,但它没有提供任何方式来访问Parent实例变量。

示例:让我们说父类存储一个包含名称的String。我想要一个孩子来自父母,他的String名字是"乔治"还有一个孩子来自父母,他的String名字是"尼克"。当String存储在" George"父母班级改变了"乔治"到了#Patrick; Patrick"我希望它能为他的孩子改变,但不是为了" Nick"。

的孩子

这可以在没有太多计算开销的情况下完成吗?

代码参考

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

public class Child extends Parent {
    private String parentName;
    /**
     * Currently derives the String directly which won't react to
     * changes to the Parent class.
     */
    public Child(Parent p) {
        this.parentName = p.getName();
    }

    public getParentName() {
        return parentName;
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);

        George.changeName("Patrick");

        // Prints "George", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());
    }
}

解决方案:实际上可以使用Object Composition来实现上述目标。

通过保留对创建Parent类实例时使用的原始Child的引用,Parent实例上执行的所有更改都将反映在Child上实例。

通过这种方式,Child也可以处于孤立状态,其中没有Parent实例用于创建它。

解决方案代码

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

// Extension is not required
public class Child {
    private Parent parentReference;

    public Child(Parent parentReference) {
        this.parentReference = parentReference;
    }

    public getParentName() {
        // We need to manually handle the case of a non-existent parent
        if (parentReference == null) {
            return "None";
        } else {
            return parentReference.getName();
        }
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);
        Child c = new Child(null);

        George.changeName("Patrick");

        // Prints "Patrick", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());

        // Prints "None", should print "None"
        System.out.println(c.getParentName());
    }
}

2 个答案:

答案 0 :(得分:2)

您正在接受条款"家长"和"孩子"在你的例子中非常字面意义,但并不总是适用。

只有在类型和子类型之间存在固定关系时,才能使用继承。喜欢,"自行车是一种车辆"或者"长颈鹿是动物"。对于自行车和长颈鹿的每一个例子,这些关系是相同的。但你所描述的并不是这样的。

对于您的情况,您可以使用合成来建模。

  • 每个Person都有name
  • 每个Person都有一个parent(可能会留下null表示“不知道”#34}或“#”关心")
  • 每个Person都有零个或多个children
class Person {
    String name;
    Person parent;

    Person(String name, Person parent) {
        this.name = name;
        this.parent = parent;
    }

    // etc (getters, setters)
}

public class MainApp {
    public static void main(String[] cmdArgs) {
        Person george = new Person("George", null);
        Person nick = new Person("Nick", null);
        Person a = new Person("a", george);
        Person b = new Person("b", george);
        Person c = new Person("c", nick);
        // etc.
    }
}

答案 1 :(得分:1)

将继承用于实际陈述的问题,它会非常复杂,当你开始扩展你的服务时你会遇到问题(组合将是一个更好的现实世界的方法,但是组合带来更大的学习曲线,但是给出了增加了更大灵活性的好处):

public abstract class ServiceProvider {

  private String providerName;
  private String clientName;

  public ServiceProvider(String providerName, String clientName) {
    this.providerName = providerName;
    this.clientName = clientName;
  }

  public String getProviderName() {
    return this.providerName;
  }

  public String getClientName() {
    return this.clientName;
  }

  boolean validateContract();

}

public class MobileInternetProvider extends ServiceProvider {

  public MobileInternetProvider(String providerName, String clientName) {
    super(providerName, clientName);
  }

  public boolean validateContract() {
    return ContractService.validateMobileInternetProvider(this.getClientName());
  }

}

public abstract class MobileCellularProvider extends ServiceProvider {

  public MobileCellularProvider(String providerName, String clientName) {
    super(providerName, clientName);
  }

  public boolean validateContract() {
    return ContractService.validateMobileCellularProvider(getContractNumber());
  }

  String getContractNumber();

}

public class MobileCellularProviderCardContract extends MobileCellularProvider {

  public MobileCellularProviderCardContract(String providerName, String clientName) {
    super(providerName, clientName);
  }

  public String getContractNumber() {
    MobileContractService.getCardContractNumber(this.getClientName());
  }

}

public class MobileCellularProviderMobileContract extends MobileCellularProvider {

  public MobileCellularProviderMobileContract(String providerName, String clientName) {
    super(providerName, clientName);
  }

  public String getContractNumber() {
    MobileContractService.getMobileContractNumber(this.getClientName());
  }

}

然后你会像这样使用它:

ArrayList<ServiceProvider> serviceProviders = new ArrayList<>();
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 1"));
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 2"));
serviceProviders.add(new MobileCellularProviderCardContract(ProviderDef.PROVIDER_1, "Client 3"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_1, "Client 4"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_2, "Client 1"));

原始回答

当实例化子类时,它具有超类'字段,因此更新子类'name字段和更新超类'name字段之间没有区别......只有一个字段在实例中。

所以当你说:

  

例如,假设父类存储包含名称的String。我希望3个孩子来自一个名字为“George”的父母,另外3个孩子来自一个名字为“Nick”的父母。当存储在“乔治”父类中的字符串从“乔治”变为“帕特里克”时,我希望为其子项更改它,而不是为“尼克”的子项更改。

这没有用。

你问题的标题是

  

是否有任何方法可以让父类的实例的变量直接被其子类(子类)引用?

答案是肯定的!但是您描述的问题与问题的标题无关