Java - 通过扩展克隆
Java - cloning through extending
设想情况:
我有两个类
public class Fruit{
}
和:
public class FruitOnSale extends Fruit{
int price;
public int getPrice() or something
}
我的程序有一个水果和一个 fruitOnSale 对象。我想创建基于 fruitOnSale 的全新(克隆)fruit2 [Fruit](例如有人购买了 fruitOnSale 并且它需要出现在他的包中但作为普通水果因为它不再在商店中)。 getPrice 方法和price 字段在此期间被删除。
然后向后 - 有人创建了一家商店(...)并出售他的水果。现在我需要将水果转换为 FruitOnSale(我希望它在商店中作为 'on sale',在我的包中作为 'normal',但作为独立对象)。
这些 类 将被重建、修改并且可能对它们进行大量工作,所以我不想通过复制每个字段来手动重写它们,因为它是无意义的。通过克隆有可能吗?或者你有更好的想法吗?
使用构图:
public class Fruit {
// your regular fruit class
}
你的"fruit on sale":
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());
}
}
现在你可以通过传入一个Fruit
实例来构造FruitOnSale
实例,你也可以从FruitOnSale
实例中得到一个Fruit
实例。请注意,当您使用 Fruit
实例初始化 FruitOnSale
实例时,它会创建 Fruit
实例的 "copy"。这样做很好,否则您可以修改原始 Fruit
实例,这将影响 FruitOnSale
实例。如果您假设这些是不可变的,那么这不是您想要的。同样,getFruit()
没有 return 对内部实例的引用,但也创建了一个全新的 Fruit
实例。
虽然使用继承解决这个特定示例并不违反 Liskov Substitution Principle,但通常考虑扩展基数 class 的影响是个好主意。例如,可能有些事情可以用 Fruit
做,但用 FruitOnSale
就没有意义(即可能导致不一致、不合逻辑或不可预测的行为);这将是违反 LSP 的一个例子。
克隆和继承是两个截然不同且毫不相关的概念,如果我对您的理解正确的话,两者都不太可能对您当前的情况有所帮助。
克隆通常是指您希望在运行时复制现有对象,因此在编程上下文中应避免使用该术语,除非主题实际上与对象克隆的概念相关。
继承用于您想要提供更具体的版本或替代某物的实现,从而扩展更多vague/abstract版本的功能addition/altered 功能。
举个例子,我们可以声明两个class如下:
public class WoodenFurniture{
public void burn(){
// Implementation here
}
}
和
public class WoodenChair extends WoodenFurniture{
public void sit(){
// Implementation here
}
}
请注意,在这种情况下,WoodenChair
是 WoodenFurniture
的更具体版本,因此 WoodenChair
继承了 [=14] 的所有功能 =],包括前面提到的burn()
方法。
虽然您的 Fruit
和 FruitOnSale
class 证明了这种关系,其中 FruitOnSale
是 Fruit
的更具体版本,您的继承申请不正确。
在你的问题正文中,你建议在携带不同信息的多个状态之间改变一个 Fruit
对象应该通过继承来完成,只有当你不断地向当前对象添加或指定细节时才是正确的。在这种特殊情况下,应该使用组合,如 Vivin Paliath 所述。
但在您所描述的情况下,您想要在同一对象的不同状态之间反复更改或切换。特别是通过说 method getPrice and field price are deleted during it
你证明 继承不是你想要的。 这应该通过向你的原始对象添加字段来附加特定于状态的信息而不是创建多个class,如下:
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;
}
}
上面的 class 表示您想要的内容的示例实现。在这种情况下,我们不需要经历对象类型之间转换的麻烦,也不需要破坏任何关于对象应该如何交互的继承策略。
设想情况:
我有两个类
public class Fruit{
}
和:
public class FruitOnSale extends Fruit{
int price;
public int getPrice() or something
}
我的程序有一个水果和一个 fruitOnSale 对象。我想创建基于 fruitOnSale 的全新(克隆)fruit2 [Fruit](例如有人购买了 fruitOnSale 并且它需要出现在他的包中但作为普通水果因为它不再在商店中)。 getPrice 方法和price 字段在此期间被删除。 然后向后 - 有人创建了一家商店(...)并出售他的水果。现在我需要将水果转换为 FruitOnSale(我希望它在商店中作为 'on sale',在我的包中作为 'normal',但作为独立对象)。
这些 类 将被重建、修改并且可能对它们进行大量工作,所以我不想通过复制每个字段来手动重写它们,因为它是无意义的。通过克隆有可能吗?或者你有更好的想法吗?
使用构图:
public class Fruit {
// your regular fruit class
}
你的"fruit on sale":
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());
}
}
现在你可以通过传入一个Fruit
实例来构造FruitOnSale
实例,你也可以从FruitOnSale
实例中得到一个Fruit
实例。请注意,当您使用 Fruit
实例初始化 FruitOnSale
实例时,它会创建 Fruit
实例的 "copy"。这样做很好,否则您可以修改原始 Fruit
实例,这将影响 FruitOnSale
实例。如果您假设这些是不可变的,那么这不是您想要的。同样,getFruit()
没有 return 对内部实例的引用,但也创建了一个全新的 Fruit
实例。
虽然使用继承解决这个特定示例并不违反 Liskov Substitution Principle,但通常考虑扩展基数 class 的影响是个好主意。例如,可能有些事情可以用 Fruit
做,但用 FruitOnSale
就没有意义(即可能导致不一致、不合逻辑或不可预测的行为);这将是违反 LSP 的一个例子。
克隆和继承是两个截然不同且毫不相关的概念,如果我对您的理解正确的话,两者都不太可能对您当前的情况有所帮助。
克隆通常是指您希望在运行时复制现有对象,因此在编程上下文中应避免使用该术语,除非主题实际上与对象克隆的概念相关。
继承用于您想要提供更具体的版本或替代某物的实现,从而扩展更多vague/abstract版本的功能addition/altered 功能。
举个例子,我们可以声明两个class如下:
public class WoodenFurniture{
public void burn(){
// Implementation here
}
}
和
public class WoodenChair extends WoodenFurniture{
public void sit(){
// Implementation here
}
}
请注意,在这种情况下,WoodenChair
是 WoodenFurniture
的更具体版本,因此 WoodenChair
继承了 [=14] 的所有功能 =],包括前面提到的burn()
方法。
虽然您的 Fruit
和 FruitOnSale
class 证明了这种关系,其中 FruitOnSale
是 Fruit
的更具体版本,您的继承申请不正确。
在你的问题正文中,你建议在携带不同信息的多个状态之间改变一个 Fruit
对象应该通过继承来完成,只有当你不断地向当前对象添加或指定细节时才是正确的。在这种特殊情况下,应该使用组合,如 Vivin Paliath 所述。
但在您所描述的情况下,您想要在同一对象的不同状态之间反复更改或切换。特别是通过说 method getPrice and field price are deleted during it
你证明 继承不是你想要的。 这应该通过向你的原始对象添加字段来附加特定于状态的信息而不是创建多个class,如下:
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;
}
}
上面的 class 表示您想要的内容的示例实现。在这种情况下,我们不需要经历对象类型之间转换的麻烦,也不需要破坏任何关于对象应该如何交互的继承策略。