如何使用Java OOP概念建模按夜计费房产租赁系统的关联关系
核心问题解答
1. 必须单独定义业主类,原Property中的ownerName属性建议移除
遵循单一职责原则,业主是独立的业务实体,除姓名外还会有ID、联系方式、结算账户等专属属性,不适合耦合在房产类中。且业主和房产是典型的一对多关联关系,由业主类持有房产集合的设计扩展性更好,后续新增业主相关的业务逻辑(比如佣金结算、房源上下架管理)也更方便。
2. 业主与房产的关联实现方案
- 首先优化
Property基类:移除ownerName,新增ownerId字段做反向关联(方便快速查询房产所属业主),同时补充日期维度的占用状态存储(满足按日期预订的需求),补全占用状态相关的get/set方法。 - 定义
Owner业主类:核心包含业主基础属性 + 名下房产集合,提供房源的新增/移除/可用查询方法。
代码示例如下:
// 优化后的Property基类 public class Property { private String description; private int propertyPrice; private Long ownerId; // 关联业主ID,用于反向查询 // 替换原isOccupied,存储不同日期的占用状态,key为预订日期,value为是否已被占用 private Map<LocalDate, Boolean> occupancyMap = new HashMap<>(); // 原有get/set保留,新增占用状态校验方法 public boolean isAvailable(LocalDate date) { return !occupancyMap.getOrDefault(date, false); } public void setOccupied(LocalDate date, boolean isOccupied) { occupancyMap.put(date, isOccupied); } public Long getOwnerId() { return ownerId; } public void setOwnerId(Long ownerId) { this.ownerId = ownerId; } } // 业主类定义 public class Owner { private Long ownerId; private String name; private String contactInfo; // 持有名下所有房产的集合 private List<Property> properties = new ArrayList<>(); // 新增房产到业主名下 public void addProperty(Property property) { property.setOwnerId(this.ownerId); properties.add(property); } // 查询业主名下指定日期可用的房产 public List<Property> getAvailableProperties(LocalDate date) { return properties.stream() .filter(p -> p.isAvailable(date)) .collect(Collectors.toList()); } // 其他get/set方法省略 } // 客户类定义(预订主体必须单独建模) public class Customer { private Long customerId; private String name; private String contactInfo; // 可加预订记录集合,存储客户的历史预订信息 private List<BookingRecord> bookingRecords = new ArrayList<>(); // 其他get/set方法省略 }
3. registry函数预置条件实现逻辑
首先需要一个全局的系统上下文类,存储系统预置的业主、客户、所有房产的索引数据,初始化阶段就把预置数据加载完成:
// 系统上下文类,存储全局数据 public class RentalSystemContext { public static Map<Long, Owner> ownerMap = new HashMap<>(); public static Map<Long, Customer> customerMap = new HashMap<>(); public static Map<Long, Property> allPropertyMap = new HashMap<>(); private static Long propertyIdGenerator = 1L; // 系统初始化方法,实现预置条件 public static void init() { // 1. 初始化2个业主 Owner owner1 = new Owner(1L, "业主1", "联系电话1"); Owner owner2 = new Owner(2L, "业主2", "联系电话2"); ownerMap.put(owner1.getOwnerId(), owner1); ownerMap.put(owner2.getOwnerId(), owner2); // 2. 初始化1号业主的房产:10间30美元标准酒店房,3间60美元套房 for (int i = 0; i < 10; i++) { Hotel standardRoom = new Hotel(); standardRoom.setDescription("标准酒店客房-" + i); standardRoom.setPropertyPrice(30); standardRoom.setRoomType("Standard"); // 优化原Hotel类,单个实例存对应房型即可 owner1.addProperty(standardRoom); allPropertyMap.put(generatePropertyId(), standardRoom); } for (int i = 0; i < 3; i++) { Hotel suiteRoom = new Hotel(); suiteRoom.setDescription("套房酒店客房-" + i); suiteRoom.setPropertyPrice(60); suiteRoom.setRoomType("Suite"); owner1.addProperty(suiteRoom); allPropertyMap.put(generatePropertyId(), suiteRoom); } // 3. 初始化2号业主的房产:3套70美元公寓,5套20美元民宿 for (int i = 0; i < 3; i++) { Apartment apartment = new Apartment(); apartment.setDescription("公寓-" + i); apartment.setPropertyPrice(70); owner2.addProperty(apartment); allPropertyMap.put(generatePropertyId(), apartment); } for (int i = 0; i < 5; i++) { HomestayRoom homestay = new HomestayRoom(); homestay.setDescription("民宿-" + i); homestay.setPropertyPrice(20); owner2.addProperty(homestay); allPropertyMap.put(generatePropertyId(), homestay); } // 4. 初始化2个客户 Customer customer1 = new Customer(1L, "客户1", "联系电话A"); Customer customer2 = new Customer(2L, "客户2", "联系电话B"); customerMap.put(customer1.getCustomerId(), customer1); customerMap.put(customer2.getCustomerId(), customer2); } private static Long generatePropertyId() { return propertyIdGenerator++; } }
registry函数实现,先校验所有预置条件再执行预订:
/** * 预订函数 * @param customerId 客户ID * @param bookDate 预订日期 * @param propertyIds 要预订的房产ID列表 * @return 预订是否成功 */ public boolean registry(Long customerId, LocalDate bookDate, List<Long> propertyIds) { // 预置条件校验1:客户是否已注册 if (!RentalSystemContext.customerMap.containsKey(customerId)) { throw new IllegalArgumentException("客户未注册"); } // 预置条件校验2:所有预订房产在指定日期是否可用 for (Long propertyId : propertyIds) { Property property = RentalSystemContext.allPropertyMap.get(propertyId); if (property == null || !property.isAvailable(bookDate)) { throw new IllegalArgumentException("房产ID:" + propertyId + " 不存在或指定日期已被预订"); } } // 校验通过,执行预订 for (Long propertyId : propertyIds) { Property property = RentalSystemContext.allPropertyMap.get(propertyId); property.setOccupied(bookDate, true); // 可补充生成预订记录、关联到客户的预订列表等逻辑 } return true; }
现有代码优化提示
你当前的Hotel类用数组存储所有房型和数量的设计不合理,因为每个房间都是独立的可预订单元,建议把roomType改为单个字符串属性,每个Hotel实例对应一间具体的酒店客房,和公寓、民宿的实例粒度保持一致,后续预订逻辑不需要做特殊适配。
内容的提问来源于stack exchange,提问作者Dionisius Pratama
相关产品推荐
相关产品推荐

