子类和超类

Sublass and superclass

我需要有关创建子类的帮助,子类不会覆盖父类方法。我使用注册表对象来收集所有项目。

public class Registry {
private final Item[] items = new Item[100];
private int pos =0;

public Item[] getItems(){

    return items;
}

public void addItem(Item item) {

    items[pos] = item;
    pos ++;
}
public void addItem(Item item, int nrTimes) {

    for(int i = 0; i<nrTimes;i++){
        items[pos] = item;
        pos++;
    }
}
public double totPrice(){

    double total = 0.0;
    for(int i = 0; i < items.length; i ++){
        if(items[i] == null) break;
        total += items[i].getNr(this);

    }
    return total;
}

public String toString() {
    String result = "";

    for(int i= 0; i < items.length;i++){
        if (items[i] == null) break;
           result = result + items[i].getName()+" $" + items[i].getNr(this) + " Sold by " + items[i].getName2()+ "\n";

    }
    return result;
}

}

public class Item {
private final String name;
private final String name2;
private final double nr1;

public Item (String name, String name2, double nr1) {
    this.name = name; this.name2 = name2; this.nr1 = nr1;
}

public Item (Item obj) {
    name = obj.name; name2 = obj.name2; nr1 = obj.nr1;
}

public double getNr(Registry reg) { return nr1;}

public final String getName() { return name;}

public final String getName2() { return name2;}

}

子类

public class ReducedItem extends Item {
private final Item obj = this;
private final double reduce; // in %

public ReducedItem (Item obj, double reduce) {
    super(obj);
    this.reduce = reduce/100;
}

public double getNr(Registry reg){
    double nr;
    nr = super.getNr(reg) - (super.getNr(reg)*reduce);
    return nr;
}

}

这里是我创建对象的主要地方

     import java.util.*;
     public class Main {
      static Scanner scan = new Scanner(System.in);
      public static void registerItems(Registry reg){
       String name,seller;
       double price;
       int nrprod,discount;
       scan.nextLine();
       System.out.print("Product name: ");
       name = scan.nextLine();

       System.out.print("Seller: ");

       seller = scan.nextLine();

       System.out.print("Price: ");
       price = scan.nextDouble();
       System.out.print("How many: ");
       nrprod = scan.nextInt();
       System.out.print("Discount (enter 0 if no discount applies): ");
       discount = scan.nextInt();

       Item item = new Item(name,seller,price);
       if(discount >0) {
          ReducedItem redItem = new ReducedItem(item, discount);
          if(nrprod == 1){
             reg.addItem(redItem); 
         }else{
             reg.addItem(redItem, nrprod);
         }

     }else{
         if(nrprod == 1){
             reg.addItem(item);
         }else{
             reg.addItem(item, nrprod);
         }
     }

 }

public static void main(String[] args) {
    System.out.println("Welcome");
    System.out.println("What's your name?");
     String customer = scan.nextLine();
     System.out.println("Hi "+customer+". Please choose one of the following options:");
     System.out.print("buy product (1) or checkout (0)");


     Registry reg = new Registry();
     int input = scan.nextInt();
     while(input == 1){
         registerItems(reg);
         System.out.println("buy product (1) or checkout (0)");
         input = scan.nextInt();
     }
     System.out.println(reg.toString());
     System.out.println("Your total is " + reg.totPrice());

}

}

在registerItems中输入

    Product name = Car
    Seller = Jack
    Price = 10000
    how many =1
    discount = 20
    checkout = 0

输出

    Car 00 Sold by jack

    Your total is 8000.0

现车优惠20%

这是我认为您正在寻找的工作示例。

public class J_crow {
  public static void main(String... args) {
    Item item = new Item("Name One", "Second Name", 42);
    System.out.println(item);
    Item reducedItem = new ReducedItem(item, 20);
    System.out.println(reducedItem);
  }
}

class Item {
  private final String name;
  private final String name2;
  private final double nr1;

  public Item(String name, String name2, double nr1) {
    this.name = name;
    this.name2 = name2;
    this.nr1 = nr1;
  }

  public Item(Item obj) {
    this(obj.getName(), obj.getName2(), obj.getNr());
  }

  public double getNr() {
    return nr1;
  }

  @Override
  public String toString() {
    return String.format("I am an [%s], I cost [%f]", getClass().getCanonicalName(), getNr());
  }

  public String getName2() {
    return name2;
  }

  public String getName() {
    return name;
  }
}

class ReducedItem extends Item {
  private final double reduce; // in %

  public ReducedItem(Item obj, double reduce) {
    super(obj);
    this.reduce = reduce;
  }

  @Override
  public double getNr() {
    return super.getNr() * (1 - (reduce / 100d));
  }
}

输出:

 I am an [Item], I cost [42.000000]
 I am an [ReducedItem], I cost [33.600000]

错误解释

您的错误出现在 Registry class 中的以下几行中。 (我得到了你之前发布的源代码。)

public void addItem(Item item) {
    items[pos] = new Item(item);
    pos ++;
}

您无缘无故地创建了一个全新的 Item,即使客户想要添加一个 ReducedItem,所以您实际上是在 删除 通过将 ReducedItems 替换为 Items 并导致 ReducedItem.getNr 过载到 never 来进行折扣。如果您 运行 在调试器中逐步执行代码,您应该能够看到。

这一行应该只是 items[pos++] = item;.

另请注意,您的 Registry class 存在一些问题和隐藏的错误。例如,

  1. 这个错误也出现在不必要的 addItem(Item, int) 方法重载中;
  2. 错误命名的 getNr 方法期望 Registry 的实例然后不将其用于任何事情;
  3. 向您的注册表添加足够的项目,当 pos 大于 items.length;
  4. 时,您将遇到索引超出范围异常
  5. Registry 效率非常低,浪费了很多 space(例如 new Item[100]),然后每次都循环所有 100 个,即使很少或没有项目已添加。

还有其他几个问题我不会讨论,所以我建议您将您的代码与我在下面的建议进行比较,然后了解它们为何不同。


代码重新设计

您提供的代码有几个编译错误并且难以使用。相反,我试图了解您正在尝试做什么,并重构了代码,希望能澄清一些事情,同时向您展示一些您应该考虑改进和简化代码的事情。

请注意,您需要改编我在这里写的内容。

总结

我创建了一个 Example class 来表示应用程序。它使用 ItemRegistry 来注册 Items。 Item 接口RegularItem(即没有折扣的Item)和ItemDiscount实现,这是一个例子Decorator Design Pattern.

Item接口:

public interface Item {
    String getName();
    double getCost();
}

这应该很简单:基本上已经声明了一个类型。通常,您应该优先使用接口来指定新类型,因为它允许应用程序的其余部分依赖 合同协议 (即规范)而不是 实现细节(即class)。这就是接口的用途。

警告:您真的不应该在实际应用程序中使用浮点类型来处理金钱。基本上是由于舍入误差的累积会慢慢导致你的结果不正确。有关详细信息,请参阅 this post。我在这里使用它是因为这是一个简单的玩具示例。

RegularItem Class:

public class RegularItem implements Item {
    private String name;
    private double cost;

    public RegularItem(String name, double cost) {
        this.name = name;
        this.cost = cost;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getCost() {
        return cost;
    }
}

这应该是不言自明的:具有名称及其相关成本的项目的简单实现。常规项目没有应用折扣。 ItemDiscount class.

事情开始变得更有趣

ItemDiscount Class(装饰器)

// Decorator class
public class ItemDiscount implements Item {
    private Item item;
    private double discount;

    public ItemDiscount(Item it, double amount) {
        item = it;
        discount = amount / 100.0; // e.g. 15/100 = 15%
    }

    @Override
    public String getName() {
        return item.getName();
    }

    @Override
    public double getCost() {
        return item.getCost() - (item.getCost() * discount);
    }
}

它基本上包装了任何 Item 需要应用折扣的东西,以及 returns 客户请求 Item 的成本时的折扣成本。这有几个优点:

  1. 客户只看到Items,不知道哪些有折扣,哪些没有。没必要。
  2. 您可以对同一商品应用任意数量的折扣(例如,客户有 5 张折扣券?没问题!)
  3. 您的应用程序更易于理解和维护

还有更多,但我现在不去那里。让我们跟进下面的ItemRegistry

ItemRegistry Class

import java.util.ArrayList;
import java.util.List;

public class ItemRegistry {
    private List<Item> items = new ArrayList<Item>();

    public ItemRegistry() {}

    void registerItem(Item i) {
        items.add(i);
    }

    double getTotalCost() {
        double total = 0.0;
        for(Item i : items)
            total += i.getCost();
        return total;
    }

    List<Item> getItems() {
        return items;
    }
}

注意这个简化版本中的几件事。

  1. class不需要处理折扣或非折扣的“特殊情况”。 (还记得有 5 张优惠券的顾客吗?这里不需要更改!)
  2. class 使用 接口 而不是 classes 进行通信,后者是应该保持封装的实现细节。

请注意,注册表不需要了解它拥有的项目的具体类型——只需要知道它们是项目即可。 (您不希望每次定义一种新的项目时都必须更新整个应用程序,或者更糟的是,强迫那些需要维护您的代码的人这样做,做你?)

使用注册表的客户端也不需要知道它使用的是 ArrayList 还是其他东西——只需要知道它是 List。这使其更 space 高效,并修复了您的代码在添加 100 多个项目后会遇到的错误。

您可以在下面的 Example class 中看到它,因为它使用了 ItemRegistry:

Example Class(申请)

public class Example {
    public static void main(String[] args) {
        ItemRegistry reg = new ItemRegistry();
        reg.registerItem(new RegularItem("Toy Gun", 10));
        reg.registerItem(new ItemDiscount(new RegularItem("Toy Car", 100), 10));  // apply 10% discount to Toy Car item

        for(Item item : reg.getItems()) {
            System.out.println("Name: " + item.getName());
            System.out.println("Cost: " + item.getCost());
        }
        System.out.println("Total: " + reg.getTotalCost());
    }
}

此示例应该可以让您更轻松地在调试器中逐步执行代码,以便您可以了解如何调用方法以及覆盖的实际工作方式。

程序输出:

Name: Toy Gun
Cost: 10.0
Name: Toy Car
Cost: 90.0
Total: 100.0

而且是正确的:)

我太笨了!我解决了我的问题

public void addItem(Item item) {

    items[pos] = new Item(item);
    pos ++;
}
public void addItem(Item item, int nrTimes) {

    for(int i = 0; i<nrTimes;i++){
        items[pos] = new Item(item);
        pos++;
    }
}

我每次都创建一个新的Item,我需要使用传递的参数来代替

public void addItem(Item item) {

    items[pos] = item;
    pos ++;
}
public void addItem(Item item, int nrTimes) {

    for(int i = 0; i<nrTimes;i++){
        items[pos] = item;
        pos++;
    }
} 

谢谢,看了你的回答和评论我学到了很多东西