2015-09-17 11 views
7

Ví dụ:Cách tốt nhất để điều hướng một cây phức tạp của các đối tượng khác nhau là gì?

class Vehicle { 
    Collection<Axle> axles; 
} 

class Axle { 
    Collection<Wheel> wheels; 
} 

class Wheel { 
    // I think there are dually rims that take two tires -- just go with it 
    Collection<Tire> tires; 
} 

class Tire { 
    int width; 
    int diameter; 
} 

Tôi có một dịch vụ mà qua đó tôi có thể có được một bộ sưu tập của tất cả các đối tượng xe tôi biết về. Bây giờ nói rằng tôi có một lốp xe có chiều rộng và đường kính cụ thể, và tôi muốn tìm một chiếc xe có thể mang nó. Cách đơn giản là có một bộ bốn vòng lồng nhau, như vậy:

for (Vehicle vehicle : vehicles) { 
    for (Axle axle : vehicle.getAxles()) { 
     for (Wheel wheel : axle.getWheels()) { 
      for (Tire tire : wheel.getTires()) { 
       if (tire.width == targetWidth 
       && tire.diameter == targetDiameter) { 
        // do something 
        break; 
       } 
      } 
     } 
    } 
} 

Có mẫu thiết kế tốt cho điều này không? Hoặc một cấu trúc dữ liệu tốt hơn để sử dụng? Nó sẽ được tốt hơn để chỉ giữ một chỉ số một nơi nào đó của thông tin lốp ánh xạ tới xe?

chỉnh sửa: trả lời câu hỏi từ ý kiến ​​

Bạn có thể kiểm soát cấu trúc của dữ liệu bạn nhận được từ các dịch vụ?

Bạn cần phải tìm kiếm cho lốp xe khác nhau nhiều lần trong cùng một dữ liệu?

là hiệu suất là một vấn đề?

Không đặc biệt

Khi bạn tìm thấy lốp, bạn chỉ cần biết đó xe chứa nó hay bạn cũng cần trục và bánh xe?

Đôi khi chỉ là phương tiện, đôi khi chỉ cần trục - hai hoàn cảnh khác nhau

Bạn có cần tham chiếu đến lốp đã được tìm thấy?

Vâng, trong các trường hợp mà tôi cần trục

edit2: Mở rộng ẩn dụ hơn nữa, để giải thích hai bối cảnh trên:

Bối cảnh 1 - Tôi muốn biết xe, vì vậy tôi có thể gửi một nhân viên ra ngoài để lấy xe và mang nó trở lại

Bối cảnh 2 - Tôi muốn biết trục và lốp xe, vì tôi đang ở phương tiện đang cố gắng thực hiện công việc

+0

Nó phụ thuộc ... Bạn có kiểm soát cấu trúc dữ liệu bạn nhận được từ dịch vụ? Bạn có cần tìm kiếm các loại lốp khác nhau nhiều lần trong cùng một dữ liệu không? Hiệu suất có phải là vấn đề không? Khi bạn tìm thấy lốp xe, bạn chỉ cần biết chiếc xe có chứa nó hay bạn cũng cần trục và bánh xe? Bạn có cần tham chiếu đến lốp xe đã được tìm thấy không? – Cinnam

+0

Tôi đã trả lời trong bài đăng. Cảm ơn bạn đã tìm kiếm! –

+0

Vấn đề này có vẻ khiến tôi liên quan đến Luật Demeter (nguyên tắc này nhiều hơn một "luật"). Xem http://stackoverflow.com/q/12284057/1168342 – Fuhrmanator

Trả lời

2

Bạn có thể làm phẳng các vòng bằng cách sử dụng Java 8 streams.

vehicles.stream() 
    .flatMap(vehicle -> vehicle.getAxles().stream()) 
    .flatMap(axle -> axle.getWheels().stream()) 
    .flatMap(wheel -> wheel.getTires().stream()) 
    .filter(tire -> tire.width == targetWidth 
      && tire.diameter == targetDiameter) 
    .forEach(tire -> { 
     // do something 
    }); 

Những điều tốt đẹp về con suối là bạn có thể chèn thêm filter, filter, findAny vv, gọi khá dễ dàng ở bất cứ đâu trong chuỗi.

+0

Có thể truy cập xe và trục có chứa khi lốp xe được tìm thấy hoặc các lớp học có cần phải có một số tài liệu tham khảo về cha mẹ không? – Cinnam

+0

@Cinnam - Không giống như nó - Tôi vừa xây dựng một ứng dụng thử nghiệm cho ví dụ về xe và mã trong khối forEach không thể tham chiếu bất kỳ thứ gì bên trên lốp xe. –

0

Miễn là không có quá nhiều mục và/hoặc hiệu suất không phải là một vấn đề lớn, tôi có thể chỉ cần đi với các vòng lồng nhau (hoặc suối từ câu trả lời của John).

Vì bạn có hai bối cảnh cho việc tìm kiếm, bạn có thể vượt qua các hành động thích hợp với phương pháp tìm kiếm - một cái gì đó như thế này (sử dụng vòng lặp trong trường hợp này):

interface TireAction { 
    void doSomething(Vehicle v, Axle a, Tire t); 
} 

void findTireAndPerform(int targetWidth, int targetDiameter, TireAction action) { 
    for (Vehicle vehicle : vehicles) { 
     for (Axle axle : vehicle.getAxles()) { 
      for (Wheel wheel : axle.getWheels()) { 
       for (Tire tire : wheel.getTires()) { 
        if (tire.width == targetWidth && tire.diameter == targetDiameter) { 
         action.doSomething(vehicle, axle, tire); 
         break; 
        } 
       } 
      } 
     } 
    } 
} 

void someMethod() { 
    ... 

    findTireAndPerform(width, diameter, (v, a, t) -> { 
     // send worker to 'v' 
    }); 

    ... 

    findTireAndPerform(width, diameter, (v, a, t) -> { 
     // work on 'a' and 't' 
    }); 
} 
+0

Vâng, tôi càng nghĩ về nó và nghiên cứu, tôi càng nghĩ đến việc giữ vòng lặp. Mặc dù vậy, nó được xếp hạng. –

+0

@SamJones Vâng, nó có thể không phải là điều đẹp nhất :) Nhưng trong trường hợp này tôi không nghĩ rằng nó không phù hợp. – Cinnam

1

Nếu không có thay đổi cấu trúc dữ liệu của bạn, bạn thắng' t có thể tạo ra sự khác biệt đáng kể. Bạn có thể thêm một số đường cú pháp với lambdas, nhưng về bản chất nó là cùng một giải pháp.

Những điều bạn có thể xem xét:

  • Mô hình của bạn cho phép Vehicles với zero trục hoặc trăm. Trong khi nó phụ thuộc vào mô hình kinh doanh của bạn nó có vẻ lạ.
  • Mô hình của bạn cho phép có các trục khác nhau trong xe, các bánh xe khác nhau. Có thực sự cần thiết không? Hãy chắc chắn rằng các yếu tố của mô hình của bạn nên có bản sắc riêng biệt của họ (hiện tại mỗi đối tượng có nó) và đó chỉ là một đối tượng giá trị.
  • Đảm bảo bạn thực sự cần mô hình chi tiết như vậy. Hiện tại bạn có hai lớp (Axle, Wheel), chỉ có các bộ sưu tập các đối tượng bên trong. Nếu chúng sẽ là đối tượng JavaBean đơn giản với getAllInnerTypes() thì bạn nên cân nhắc việc loại bỏ lớp này. Nó thậm chí có thể là trường hợp thông tin lốp nên được lưu trữ gần như trực tiếp trong lớp học Vehicle.
2

Tôi sẽ đảo ngược logic của bạn và di chuyển câu hỏi vào Vehicle, trừ khi bạn muốn giữ đồ vật của bạn mỏng vì bất kỳ lý do nào khác (trong trường hợp này, tôi sẽ quấn chúng với vật thể dày hơn để thêm bất kỳ hành vi nào cần thiết)

class Vehicle { 
    ... 

    public Tire acceptsTire(Tire tire) { 

    } 
} 

từ đây có một số khả năng, tùy thuộc vào mức độ quan trọng của logic kinh doanh này trong miền của bạn nói chung.

  1. Nếu bạn có nhiều hành động, bạn có thể chỉ lặp lại như bạn đã làm trong mẫu của mình. Hoặc có thể theo cách tương tự như tôi đã gợi ý, hãy tiếp tục xếp câu hỏi vào thành phần chính xác. Miễn là bạn có thể sống với thời gian phức tạp của việc này, điều đó sẽ ổn thôi.
  2. Nếu kiểm tra này là thứ bạn thường làm thì bạn có thể tham chiếu đến loại lốp xe bạn giữ trực tiếp trên xe, đây có thể là bộ sưu tập Tire của bạn hoặc bạn có thể vượt qua trường hợp TireSpecification khi xây dựng Vehicle nếu vì bất kỳ lý do nào bạn cần phải giữ những thứ này riêng biệt (ý định của bạn không rõ ràng trong câu hỏi, là lốp xe trên xe hay chỉ là thông số phù hợp?)
Các vấn đề liên quan