【问题标题】:Can you change a immutable class?你能改变一个不可变的类吗?
【发布时间】:2023-04-11 06:18:01
【问题描述】:

这是一个实践的理论问题。

问题是

创建一个不可变类Car

创建一些汽车实例以在 Garage 类中填充 Arraylist<Car>

MyGarage 类从Garage 实现这些方法:

  • getCar(String reg) – 搜索注册号为reg的汽车。
  • getMake(String make) – 返回与给定 make 匹配的汽车列表。
  • totalValue() – 计算列表中所有汽车的总价值。
  • changeOwner(String reg, String ow) – 将注册号为reg 的车主更改为ow

我不理解changeOwner 方法,因为我认为它不能更改不可变类的实例???

这是我为解决它所做的工作,但看起来很愚蠢

import java.util.ArrayList;

public class MyGarage implements Garage {
    
    private ArrayList<Car> myGarage;
    
    public MyGarage() {
        myGarage = new ArrayList<Car>();
    }

    @Override
    //Adds a Car if the registration is unique 
    public boolean add(Car c) {
        for(Car car : myGarage) {
            if(car.getRegistration().equals(c.getRegistration())) {                         
                System.out.println("Car has the same Registration as another illegal");
                return false;       
            }   
        }
        myGarage.add(new Car(c.getOwner(),c.getRegistration(),c.getMake(),c.getkilometres(), c.getprice()));
        return true;
    }

    @Override
    public Car getCar(String carID) {
        for(Car car : myGarage) {
            if(carID.equals(car.getRegistration())) {
                System.out.println("Car Found");
                return car;
            }
        }

        System.out.println("No car of that record");
        return null;
    }

    @Override
    public ArrayList<Car> getMake(String make) {
        
        ArrayList<Car> carModel = new ArrayList<Car>();
            for(Car car : myGarage) {
                if (car.getMake().equals(make)) {
                    carModel.add(car);
                }           
            }
        System.out.println(carModel.toString());        
        return carModel;
    }

    @Override
    public  void totalValue() {
        double amount = 0;
        for(Car car : myGarage) {
            amount = car.getprice() + amount;
        }
        System.out.println("The total amount is: " + amount);
    }

    @Override
    public boolean changeOwner(String registration, String ow) {

        for(Car car : myGarage) {
            if(car.getRegistration().equals(registration)) {
                myGarage.remove(car);
                car = new Car(ow, "444","F-50",  4, 4000.99);
                myGarage.add(car);
                return true;
            }
        }
        return false;
    }
}

【问题讨论】:

  • car = new Car(ow, "444","F-50", 4, 4000.99); - new 表示 - 你没有改变现有的 Car 你正在构建一个新的。
  • myGarage.remove(car); - 这行得通吗?
  • @ScaryWombat OP 说他们必须解决不变性问题。创建一个新的Car 是一种解决方法,但它并没有真正改变汽车的所有者——因此是个问题。
  • 根据您给出的要求,汽车似乎不能有所有者财产。也许您打算将所有者信息存储在车库而不是汽车中。
  • 不可变类通常会有返回一个克隆对象的设置器,其中相关字段已更新。在这种情况下,它隐藏在 Garage 类中,尽管我仍然会以这种方式实现它——不过,你不应该硬编码其他值;它们应该从正在更新的不可变实例中提取——并且克隆/等的责任不在于车库,而在于汽车。

标签: java oop arraylist immutability


【解决方案1】:

在面向对象和函数式编程中,不可变对象 (unchangeable object) 是一个状态不能被修改的对象 创建后。这与可变对象相反 (可变对象),创建后可以修改。在 在某些情况下,一个对象被认为是不可变的,即使一些内部 使用的属性发生了变化,但对象的状态似乎从 一个外部的观点。 - WikiPedia

因此,不可变对象是其状态在初始化后不会改变的实例。这些类型的类通常适用于需要实现某种形式的缓存以及您担心多线程环境中的线程安全(不可变对象本质上是线程安全的)的应用程序。

我没有看到您的 Car 课程,但假设它看起来像这样:

public final class Car { 

  final String registration; 
  final String owner; 

  public Car(String registration, String owner) { 
    this.registration = registration; 
    this.owner= owner; 
  } 

  public String getRegistration() { 
    return registration; 
  } 

  public String getOwner() { 
    return owner; 
  } 
} 

...请注意,此类中没有 setter 方法。因此,car 只能被初始化(即Car myCar = new Car("abcd", "John");,其中的变量(即registrationowner)永远无法更新。

因此,您的 changeOwner 方法本质上是循环遍历您的 garage 中的 car 实例,当它找到匹配的注册号时,它会从您的 garage 中删除该 car 实例,然后添加一个整体新的一个。

为了证明这一点,您可以运行以下命令:

public class Garage {

  public static void main(String ... args) {
    List<Car> myGarage = new ArrayList<>();
    myGarage.add(new Car("CG404GH", "John"));
    System.out.println(myGarage);
    for(Car car : myGarage) {
        if("CG404GH".equals(car.getRegistration())) {
            myGarage.remove(car);
            Car updateCar = new Car("DD404GH", "John");
            myGarage.add(updateCar);
        }
    }
    System.out.println(myGarage);
  }

}

这将打印出类似于以下内容的内容(@ 之后的部分在每次运行时都会有所不同):

[Car@4411d970]
[Car@6442b0a6]

这里要注意的重要一点是@后面的值是不同的,因此它们是car的两个完全不同的类(实例)

【讨论】:

    猜你喜欢
    • 2013-11-10
    • 2013-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2013-06-24
    • 1970-01-01
    • 2015-05-03
    相关资源
    最近更新 更多