[Python] Re-designing implementation to solve a Diamond problem

Discussão em 'Python' iniciado por Stack, Fevereiro 6, 2025.

  1. Stack

    Stack Membro Participativo

    Given the following toy problem involving the design of some shipping business. The business consists of multiple types of facilities, e.g. a Warehouse, and a ShippingCenter.

    class Facility:
    def __init__(self, facility_id, address):
    self.facility_id = facility_id
    self.address = address
    ... # More generic facility attributes and functions

    class Warehouse(Facility):
    def __init__(self, facility_id, address, storage_space):
    super().__init__(facility_id, address)
    self.storage_space = storage_space
    self.inventory = []

    def store_item(self, item):
    if self.storage_space >= item.size():
    self.inventory.append(item)
    self.storage_space -= item.size()
    def retrieve_item(self, item):
    ... # retrieve item and free storage space

    class ShippingCenter(Facility):
    def __init__(self, facility_id, address, drivers, sorting_belts):
    super().__init__(facility_id, address)
    self.drivers = drivers
    self.sorting_belts = sorting_belts

    def ship_item(self, item, customer):
    ... # ship stuff


    This design worked well, until we add a HybridFacility that can do both storage and shipping:

    class HybridFacility(Warehouse, ShippingCenter):
    def __init__(self, facility_id, address, storage_space, drivers, sorting_belts):
    # Not quite sure how to make the initialization work.
    # Nevertheless, it's ugly due to diamond-shaped dependency


    The addition of the HybridFacility which inherits from both Warehouse and ShippingCenter which both inherit from Facility, introduces a Diamond problem. I'm looking for a better way to model this. Here is my attempt:

    # ======= Different facility types
    class WarehouseType:
    def __init__(self, storage_space):
    self.storage_space = storage_space
    self.inventory = ...

    class ShippingCenterType:
    def __init__(self, drivers, sorting_belts):
    self.drivers = drivers
    self.sorting_belts = sorting_belts

    class HybridType(WarehouseType, ShippingCenterType):
    def __init__(self, storage_space, drivers, sorting_belts):
    WarehouseType.__init__(self, storage_space)
    ShippingCenterType.__init__(self, drivers, sorting_belts)

    # ======= Different facilities each with their own type
    class Facility:
    def __init__(self, facility_id, address, facility_type):
    self.facility_id = facility_id
    self.address = address
    self.facility_type = facility_type
    ... # More generic facility attributes and functions

    class Warehouse(Facility):
    def __init__(self, facility_id, address, storage_space):
    super().__init__(facility_id, address, WarehouseType(storage_space))

    def store_item(self, item):
    if self.facility_type.storage_space >= item.size():
    self.facility_type.inventory.append(item)
    self.facility_type.storage_space -= item.size()

    def retrieve_item(self, item):
    ... # retrieve item and free storage space

    class ShippingCenter(Facility):
    def __init__(self, facility_id, address, drivers, sorting_belts):
    super().__init__(facility_id, address, ShippingCenterType(drivers, sorting_belts))

    def ship_item(self, item, customer):
    ... # ship stuff

    class HybridFacility(Facility):
    def __init__(self, facility_id, address, storage_space, drivers, sorting_belts):
    super().__init__(facility_id, address, HybridType(storage_space, drivers, sorting_belts))


    Here is a potential main method:

    def main():
    warehouse = Warehouse("W1","address1", 10)
    shipping_center = ShippingCenter("D1","address2", 5, 3)
    hybrid_facility = HybridFacility("H1","address3", 5, 2, 2)

    facilities = [warehouse, shipping_center, hybrid_facility]

    print("Shipping centers:") # Should print D1 and H1
    for facility in facilities:
    if isinstance(facility.facility_type, ShippingCenterType):
    print(f"Shipping center: {facility.facility_id}, address: {facility.address}")


    While this new implementation solves the Diamond problem, its rather verbose, and it also seems weird to access class attributes through the FacilityType, e.g. hybrid_facility.facility_type.drivers. Any suggestions for improvement? Any design patterns that would work well?

    Update: while I did the effort to propose a solution that solves the Diamond problem, I don't know whether this is a reasonable solution, or whether a seasoned software developer would instantly reject this solution.

    Continue reading...

Compartilhe esta Página