Java - 通过扩展克隆

时间:2015-05-18 17:30:02

标签: java clone cloning

想象一下情况:

我有两个班级

public class Fruit{
}

 public class FruitOnSale extends Fruit{
     int price;
     public int getPrice() or something
 }

我的程序有一个水果和一个fruitOnSale对象。我想基于fruitOnSale创建完全新的(克隆)fruit2 [Fruit](例如有人买了fruitOnSale,它需要出现在他的包中,但作为正常的水果,因为它不再是在商店里)。方法getPrice和字段价格在此期间被删除。 然后倒退 - 有人创造了一个商店(...)并将他的水果出售。现在我需要将水果转换为FruitOnSale(我希望它在商店里出售'出售'在我的包里作为'普通',但作为独立的对象)。

这些课程将被重建,修改,并且可以对它们进行大量的工作,因此我不想仅仅通过复制每个字段来手动重写它们,因为它是无意义的。是否有可能通过克隆?或者你有更好的想法?

2 个答案:

答案 0 :(得分:3)

使用构图:

public class Fruit {
   // your regular fruit class
}

您的“水果特卖”:

public class FruitOnSale {

    private Fruit fruit;     
    private int price;

    public FruitOnSale(Fruit fruit, int price) {
        this.fruit = new Fruit(fruit.getName());
        this.price = price;
    }

    public Fruit getFruit() {
        return Fruit(fruit.getName());
    }
}

现在,您可以通过传入FruitOnSale实例来构建Fruit实例,并且您也可以从Fruit实例获取FruitOnSale实例。请注意,当您使用FruitOnSale实例初始化Fruit实例时,它会创建Fruit实例的“副本”。这样做很好,否则你可以修改原来的Fruit实例,这会影响FruitOnSale实例。如果您假设这些是不可变的,那么这不是您想要的。同样,getFruit()不会返回对内部实例的引用,但也会创建一个全新的Fruit实例。

虽然使用继承解决这个特定示例并不违反Liskov Substitution Principle,但一般来说考虑扩展基类的影响是个好主意。例如,您可以使用Fruit执行一些对FruitOnSale没有意义的事情(即,可能导致不一致,不合逻辑或不可预测的行为);这将是违反LSP的一个例子。

答案 1 :(得分:0)

克隆和继承是两个非常不同且非常不相关的概念,如果我理解正确的话,两者都不可能在你当前的情况下帮助你。

克隆通常是指您希望在运行时复制现有对象,因此在编程上下文中使用时应避免使用该术语,除非该主题实际上与对象克隆的概念相关。

继承用于要提供更具体的版本或替代实现某些内容的上下文中,从而通过添加/更改功能扩展更模糊/抽象版本的功能。

举个例子,我们可以按如下方式声明两个类:

public class WoodenFurniture{
    public void burn(){
        // Implementation here
    }
}

public class WoodenChair extends WoodenFurniture{
    public void sit(){
        // Implementation here
    }
}

请注意,在这种情况下,WoodenChairWoodenFurniture的更具体版本,因此WoodenChair 会继承WoodenFurniture的所有功能,包括上述burn()方法。

虽然您的FruitFruitOnSale类证明了这种关系,FruitOnSaleFruit的更具体版本,但您的继承应用程序不正确。

在你的问题体中,你建议在携带不同信息的多个状态之间改变Fruit对象应该通过继承来完成,这只有在你不断添加或指定当前对象的细节时才会出现。在这种特殊情况下,应使用组合物,如Vivin Paliath所述。

但是在您描述的情况下,您希望在同一对象的不同状态之间反复更改或切换。特别是通过说method getPrice and field price are deleted during it你证明继承不是你想要的。这应该通过向原始对象添加字段来附加特定于状态的信息而不是创建多个类来完成,如下:

public class Fruit{
    private boolean onSale = false;
    private int price = 0;

   /**
    * Retrieves the price of the fruit if it is on sale.
    */
    public int getPrice(){
        // Check if the fruit is in the onSale state
        if(!onSale){
            // Rather than throwing exception, you can alternatively return an invalid price e.g. -1 to denote "not for sale"
            throw new IllegalStateException("not on sale");
        }

        return price;
    }

    public void putOnSale(int price){
        this.price = price;
        onSale = true;
    }

    public void takeOffSale(){
        onSale = false;
    }
}

上面的类代表了你想要的东西的示例实现。在这种情况下,我们不需要经历在对象类型之间进行转换的麻烦,也不需要破坏有关对象如何交互的任何继承策略。