【问题标题】:Can an instance of a type class object inherit a value of instance of a parent given in js?类型类对象的实例可以继承js中给定的父实例的值吗?
【发布时间】:2020-12-17 09:44:44
【问题描述】:

我正在尝试制作一个程序,让您计算学生公寓中的一个人应该为给定的发票支付多少费用。

起初我创建了一个 Invoice 和一个 Roomie 类,一切都很好。 继续这一点,我已经实现了 Apartment 类,它有一些属性,但对于程序的逻辑来说非常重要,房间数量。

我想要发生的事情是,您可以创建一个 Apartment (myHouse) 的实例,并且每次添加 Invoice 时都会获取它的值。

class Apartment {
    constructor(id, adress, numberOfRooms) {
        this.id = id;
        this.adress = adress;
        this.numberOfRooms = numberOfRooms;
        this.roomies = [];
        this.invoices = [];
    }
    addRoomie(roomie) {
        this.roomies.push(roomie);
    }
    addInvoice(invoice) {
        this.invoices.push(invoice);
    }
}

class Invoice {
    constructor(total, type, begin, end) {
        //Ask for this!

        this.total = total;
        this.type = type;
        this.begin = begin;
        this.end = end;

        this.payed = false;
        this.totalFractionated = this.totalPerPerson();
        this.debtors = {};
    }
    totalPerPerson() {
            const { begin, end, total, numberOfRooms } = this;
            const difference = end.getTime() - begin.getTime();
            const daysOfInterval = difference / (1000 * 60 * 60 * 24);
            const totalPerDay = total / daysOfInterval;
            return totalPerDay / 5; // This 5 I wanted to be numberOfRooms specify on the Aparment class
        }

当然,我可以把super 方法和所有东西都放在一起,但是我必须每次这样指定发票的值(numberOfRooms)。

【问题讨论】:

  • 也许我误解了你提到的问题:你不想每次都打电话给 numberOfRooms ......你是使用class Invoice extends Apartment 还是只使用super

标签: javascript oop inheritance


【解决方案1】:

因此,首先,您不应该在这里使用继承,因为 Invoice 不是 Apartment 的特殊情况。

也就是说,有几种方法可以做到这一点:

  1. 当您创建一个 Invoice 时,您将 Apartment 实例传递给构造函数,以便您可以将其保存并稍后将其引用为 this.apartment.numberOfRooms
  2. 您可以将 totalPerPerson 方法移动到 Apartment 类并调用它,并传递您想要的发票索引作为参数,因为您似乎将发票保存在那里
  3. 您可以创建一个不属于这两个类的函数,并让它接收一个 Invoice 实例和一个 Apartment 实例作为参数

【讨论】:

  • 嗨,Syder,我非常喜欢您的回答,并感谢您抽出宝贵的时间来回答。考虑到我希望它成为 HTML 上的索引,您可以采取什么方法?
  • 另外,假设某个子对象想要获取其父对象的值?如何解决这个问题?
  • 我最喜欢第一种方法。在这种情况下,一旦您将公寓实例保存为发票中的成员变量,您就可以像使用 this.apartment 访问其他成员变量一样访问它
【解决方案2】:

根据经验,您可能会遗漏一些关键对象。室友与公寓没有任何关系。您可能错过了租户类。租户占用一个房间。每个租户都有一个房间实例,因此您也缺少房间类。我们还可以让房间扩展公寓,以便它可以获取公寓的属性,包括地址等。如果每月发票将被拆分,则房间中的每个租户都可以拥有发票财产,或者如果租户共同决定每月如何支付租金,则每个房间都可以拥有发票财产。这将使我们拥有以下内容。由于纯 JS 没有抽象类,所以我们将公寓设为普通类。

class Apartment {
    this.address = "1234 HackerWay, linux ln, 000000";
    this.numberOfRooms = 20;
}

class Room extends Apartment {
    constructor() {
        super();
        this.isOccupied = false;
        this.tenants = [];
        this.maximumTenantsAllowed = 2;
        this._invoice = new Invoice();
    }

    addTenant(tenant) {
        if(this.isFull) throw "Room at maximum capacity";
        this.tenants.push(tenant);
    }

    get isFull() {
        return this.tenants.length === this.maximumTenantsAllowed;
    }

    /// Returns the invoice object
    get invoice() {
        return this._invoice;
    }

    get numberOfTenants() {
        return this.tenants.length;
    }
}

class Tenant {
    constructor(tenantName) {
        this.name = tenantName;
        this._invoice = new Invoice();
    }

    get Invoice() {
        return this._invoice;
    }
}

class Invoice {

    generateInvoice(invoiceObject) {
        if(invoiceObject instanceof Room) // write logic for Room
        if(invoiceObject instanceof Tenant) // write logic for tenant
    }
}

如果有逻辑需要知道公寓是否已满,请创建一个跟踪公寓的 RealEstateAgent 类并根据需要修改房间代码。

我没有测试代码。我只是向你介绍了一个大概的想法。

【讨论】:

    【解决方案3】:

    我之前提供了一个基于 OOP 的答案,您可以在此基础上进行构建,但它有局限性。下面是一种算法方法。这只是一个可以构建的框架。

    class Apartment {
      constructor(name = "Apartment",address = "1234 HackerWay, linux ln, 000000") {
        this.address = address;
        this.name = name;
    
        // This can also be a doubly linked list but for the sake of
        // learning, we just use an array. A doubly linkedlist will allow
        // us know which room is next to which within O(1) complexity.
        // Keeping it in an array will cause at least O(n)
        this.rooms = [
          new Room(1),
          new Room(2),
          new Room(3),
          new Room(4),
          new Room(5),
        ];
      }
    
      // returns the first available room that is not filled
      // to maximum capacity
      get firstAvailableVacancy() {
        return this.rooms.find((e) => !e.isFull);
      }
    
      // returns first empty room
      get firstEmpty() {
        return this.rooms.find((e) => e.isVacant);
      }
    
      findRoomByNumber(number) {
        return this.rooms.find((e) => e.id === number);
      }
    
      get numberOfRooms() {
        return this.rooms.length;
      }
    
      get hasVacancy() {
        return Boolean(this.firstAvailableVacancy) || Boolean(this.firstEmpty);
      }
    
      get hasEmptyRoom() {
        return Boolean(this.firstEmpty);
      }
    
      /// Or whatever algorithm for calculating cost
      generateCostOfRoom(room) {
        // algorithm to generate cost of room
      }
    
      // Adds tenant to room based on if they wish to have a
      // co-tenant or not
      addTenant(tenant) {
        if (!this.hasVacancy) throw "No vacancy, check back again";
        if (tenant.acceptsCoTenant) {
          let vacantRoom = this.firstAvailableVacancy;
          if (vacantRoom.hasTenant && vacantRoom.tenants[0].acceptsCoTenant) {
            vacantRoom.addTenant(tenant);
            this.generateCostOfRoom(vacantRoom);
            tenant.room = vacantRoom;
            return vacantRoom;
          }
        } else {
          let vacantRoom = this.firstEmpty;
          if (!vacantRoom)
            throw "No vacancy, check back again or consider haviing a co-tenant";
          vacantRoom.addTenant(tenant);
          this.generateCostOfRoom(vacantRoom);
          tenant.room = vacantRoom;
          return vacantRoom;
        }
      }
    }
    
    class Room {
      constructor(roomNumber) {
        this.id = roomNumber;
        this.tenants = [];
        this.maximumTenantsAllowed = 2;
        this._invoice = new Invoice();
        this.cost = 0;
      }
    
      addTenant(tenant) {
        if (this.isFull) throw "Room at maximum capacity";
        this.tenants.push(tenant);
      }
    
      get isVacant() {
        return this.tenants.length == 0;
      }
    
      get hasTenant() {
        return this.tenants.length > 0;
      }
    
      get isFull() {
        return this.tenants.length === this.maximumTenantsAllowed;
      }
    
      /// Returns the invoice object
      get invoice() {
        return this._invoice;
      }
    
      get numberOfTenants() {
        return this.tenants.length;
      }
    }
    
    class Tenant {
      constructor(tenantName, acceptsCoTenant) {
        this.name = tenantName;
        this.acceptsCoTenant = acceptsCoTenant;
        this.room = null;
        this._invoice = new Invoice();
      }
    
      get Invoice() {
        return this._invoice;
      }
    }
    
    class Invoice {
      generate(entity) {
        if (entity instanceof Room) {
          // Write logic. You can share the cost between tenants
        }
        if (entity instanceof Tenant) {
          // Write logic. Divide tenant room cost by number of tenants in the room
        }
      }
    }
    
    let apartment = new Apartment();
    apartment.addTenant(new Tenant("Michael", false));
    apartment.addTenant(new Tenant("Joe", false));
    apartment.addTenant(new Tenant("Mary", true));
    apartment.addTenant(new Tenant("Turtle", true));
    
    let room2 = apartment.findRoomByNumber(2);
    console.log(room2.tenants);
    if(room2.hasTenant) {
        let tenant1 = room2.tenants[0];
      console.log(tenant1.Invoice);
    }
    
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-27
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-21
      相关资源
      最近更新 更多