2008-10-04 19 views
24

Nó có lẽ chỉ là tôi, đó là lý do tại sao tôi hỏi câu hỏi. Chuyên gia thông tin, Nói không hỏi và SRP thường được đề cập cùng nhau như các phương pháp hay nhất. Nhưng tôi nghĩ rằng họ đang ở tỷ lệ cược. Dưới đây là những gì tôi đang nói về:Chuyên gia/Thông báo không hỏi về tỷ lệ cược với Nguyên tắc chịu trách nhiệm duy nhất?

Mã mà ủng hộ SRP nhưng vi phạm Nói Do not Ask, Thông tin Expert:

Customer bob = ...; 
// TransferObjectFactory has to use Customer's accessors to do its work, 
// violates Tell Don't Ask 
CustomerDTO dto = TransferObjectFactory.createFrom(bob); 

Mã mà ủng hộ Nói Do not Ask/Thông tin Expert nhưng vi phạm SRP:

Customer bob = ...; 
// Now Customer is doing more than just representing the domain concept of Customer, 
// violates SRP 
CustomerDTO dto = bob.toDTO(); 

Nếu chúng thực sự có tỷ lệ cược, đó là sự chứng minh cho OCD của tôi. Nếu không, xin vui lòng điền cho tôi về cách thức các thực hành này có thể cùng tồn tại một cách hòa bình. Cảm ơn bạn.

Edit: ai đó muốn một định nghĩa của các từ ngữ -

Thông tin chuyên gia: các đối tượng có dữ liệu cần thiết cho sự vận hành nên tổ chức các hoạt động

Nói Do not Ask: đừng hỏi các đối tượng cho dữ liệu để làm việc; nói với các đối tượng để làm công việc

đơn Trách nhiệm Nguyên tắc: từng đối tượng nên có trách nhiệm trong gang tấc định nghĩa

+0

Một bản trình bày nhỏ về các thuật ngữ bạn đang sử dụng có thể hữu ích. – shoosh

+3

Câu trả lời ngắn gọn là có ... câu trả lời ngắn là đôi khi mọi người (học giả) bị mắc kẹt đầu cho đến nay, họ quên rằng lập trình không phải là một khoa học hoàn hảo, chúng tôi không có một ngôn ngữ đủ sạch sẽ để đáp ứng tất cả các nguyên tắc này. Phá vỡ nguyên tắc mà nó có ý nghĩa nhất. – Stimul8d

+1

Ví dụ thứ hai của bạn vi phạm SRP, nhưng không thực sự là một ví dụ hay về Tell Don't Ask. – koenmetsu

Trả lời

8

Tôi không nghĩ rằng họ là quá nhiều mâu thuẫn khi chúng được nhấn mạnh điều khác nhau mà sẽ làm bạn đau . Một là về cấu trúc mã để làm cho nó rõ ràng, nơi trách nhiệm cụ thể và giảm khớp nối, khác là về việc giảm các lý do để sửa đổi một lớp học.

Tất cả chúng ta đều phải đưa ra quyết định mỗi ngày về cách cấu trúc mã và những phụ thuộc chúng tôi sẵn sàng đưa vào thiết kế.

Chúng tôi đã xây dựng rất nhiều nguyên tắc hữu ích, mẫu tối đa và mẫu có thể giúp chúng tôi đưa ra quyết định.

Mỗi trong số này rất hữu ích để phát hiện các loại vấn đề khác nhau có thể có trong thiết kế của chúng tôi. Đối với bất kỳ vấn đề cụ thể mà bạn có thể nhìn vào sẽ có một điểm ngọt ở đâu đó.

Các nguyên tắc khác nhau làm mâu thuẫn lẫn nhau. Chỉ cần áp dụng mọi phần hướng dẫn bạn đã nghe hoặc đọc sẽ không làm cho thiết kế của bạn tốt hơn.

Đối với vấn đề cụ thể bạn đang xem hôm nay, bạn cần phải quyết định những yếu tố quan trọng nhất có thể gây ra đau đớn cho bạn là gì.

+0

vì vậy, _all_ Nguyên tắc RẮN ít nhất trong một số trường hợp không thể thỏa mãn đồng thời - tức là có thể gây hại và không phải là số liệu "càng nhiều số liệu càng tốt" :) – mlvljr

+6

Có thực sự. Đó là lý do tại sao lập trình là một nghệ thuật và không phải là ứng dụng mù của các quy tắc. – DJClayworth

2

Các lớp đó không có tỷ lệ cược. DTO chỉ đơn giản là phục vụ như một ống dẫn của dữ liệu từ lưu trữ được dự định để được sử dụng như một container câm. Nó chắc chắn không vi phạm SRP.

Mặt khác, phương thức .toDTO là vấn đề - tại sao Khách hàng phải chịu trách nhiệm này? Vì lợi ích của "tinh khiết", tôi sẽ có một lớp khác là công việc để tạo DTO từ các đối tượng kinh doanh như Khách hàng.

Đừng quên những nguyên tắc này là nguyên tắc, và khi bạn có thể et away với các giải pháp đơn giản cho đến khi thay đổi yêu cầu buộc vấn đề, sau đó làm như vậy. Không cần thiết phức tạp chắc chắn là một cái gì đó để tránh.

Tôi đánh giá cao, BTW, Mô hình nhanh nhẹn của Robert C. Martin, Thực tiễn và nguyên tắc cho nhiều phương pháp điều trị sâu hơn về chủ đề này.

5

Bạn có thể nói về "Không hỏi" khi bạn yêu cầu trạng thái của đối tượng để yêu cầu đối tượng làm điều gì đó.

Trong ví dụ đầu tiên của bạn TransferObjectFactory.createTừ trình chuyển đổi. Nó không cho đối tượng Customer làm điều gì đó sau khi kiểm tra trạng thái của nó.

Tôi nghĩ ví dụ đầu tiên là chính xác.

0

Tôi không đồng ý 100% hai ví dụ của bạn là đại diện, nhưng từ góc nhìn chung, bạn dường như là lý do từ giả định của hai đối tượng và chỉ có hai đối tượng.

Nếu bạn tách vấn đề ra xa hơn và tạo một (hoặc nhiều) đối tượng chuyên môn để đảm nhận trách nhiệm cá nhân của bạn, và sau đó có đối tượng điều khiển vượt qua trường hợp của các đối tượng khác đang sử dụng cho các đối tượng chuyên biệt bạn có khắc ra, bạn sẽ có thể quan sát một thỏa hiệp hạnh phúc giữa SRP (mỗi trách nhiệm đã được xử lý bởi một đối tượng chuyên biệt), và Tell Don't Ask (đối tượng điều khiển đang nói cho các đối tượng chuyên ngành đang cùng nhau làm bất cứ điều gì họ làm, với nhau).

Đó là giải pháp sáng tác dựa trên bộ điều khiển của một số loại để phối hợp và ủy quyền giữa các đối tượng khác mà không bị mired trong chi tiết nội bộ của chúng.

1

DTO với lớp chị em (như bạn có) vi phạm cả ba nguyên tắc bạn đã nêu và đóng gói, đó là lý do bạn gặp sự cố ở đây.

Bạn đang sử dụng CustomerDTO này làm gì và tại sao bạn không thể chỉ sử dụng Khách hàng và có dữ liệu DTO bên trong khách hàng? Nếu bạn không cẩn thận, CustomerDTO sẽ cần một Khách hàng và Khách hàng sẽ cần một CustomerDTO.

TellDontAsk nói rằng nếu bạn dựa trên quyết định về trạng thái của một đối tượng (ví dụ: khách hàng), thì quyết định đó phải được thực hiện bên trong chính lớp khách hàng.

Một ví dụ là nếu bạn muốn để nhắc nhở khách hàng phải trả bất kỳ hóa đơn xuất sắc, vì vậy bạn gọi

List<Bill> bills = Customer.GetOutstandingBills(); 
    PaymentReminder.RemindCustomer(customer, bills); 

đây là một sự vi phạm. Thay vào đó bạn muốn làm

Customer.RemindAboutOutstandingBills() 

(và tất nhiên bạn sẽ cần phải chuyển vào PaymentReminder dưới dạng phụ thuộc khi xây dựng khách hàng).

Thông tin Chuyên gia cho biết điều tương tự khá nhiều.

Nguyên tắc trách nhiệm đơn có thể dễ dàng bị hiểu lầm - nó nói rằng lớp khách hàng phải có một trách nhiệm, nhưng cũng phải chịu trách nhiệm nhóm dữ liệu, phương pháp và các lớp khác phù hợp với khái niệm 'Khách hàng' lớp học. Những gì cấu thành một trách nhiệm duy nhất là cực kỳ khó để xác định chính xác và tôi sẽ khuyên bạn nên đọc thêm về vấn đề này.

1

Craig Larman thảo luận này khi ông giới thiệu GRASP trong Áp dụng UML và Patterns vào Object-Oriented Phân tích và Thiết kế và Phát triển Lặp đi lặp lại (2004):

Trong một số trường hợp, một giải pháp được đề xuất bởi chuyên gia là không mong muốn, thường vì các vấn đề trong khớp nối và sự gắn kết (các nguyên tắc này được thảo luận sau trong chương này).

Ví dụ: ai chịu trách nhiệm tiết kiệm Bán hàng trong cơ sở dữ liệu? Chắc chắn, phần lớn thông tin được lưu là trong đối tượng Sale, và do đó Expert có thể cho rằng trách nhiệm nằm trong lớp Sale. Và, bằng cách mở rộng hợp lý của quyết định này, mỗi lớp sẽ có các dịch vụ riêng của mình để lưu chính nó trong một cơ sở dữ liệu. Nhưng hành động trên lý luận đó dẫn đến các vấn đề trong sự gắn kết, ghép nối và trùng lặp. Ví dụ, lớp Sale giờ đây phải chứa logic liên quan đến xử lý cơ sở dữ liệu, chẳng hạn như liên quan đến SQL và JDBC (Kết nối cơ sở dữ liệu Java). Lớp học không còn chỉ tập trung vào logic ứng dụng thuần túy là “bán hàng”. Bây giờ các loại trách nhiệm khác làm giảm sự gắn kết của nó. Lớp này phải được kết hợp với các dịch vụ cơ sở dữ liệu kỹ thuật của một hệ thống con khác, chẳng hạn như các dịch vụ JDBC, thay vì chỉ được kết hợp với các đối tượng khác trong lớp miền của các đối tượng phần mềm. Và có khả năng là logic cơ sở dữ liệu tương tự sẽ được nhân bản trong nhiều lớp liên tục.

Tất cả các sự cố này cho biết vi phạm nguyên tắc kiến ​​trúc cơ bản: thiết kế để tách mối quan tâm hệ thống chính. Giữ logic ứng dụng ở một nơi (chẳng hạn như đối tượng phần mềm tên miền), giữ logic cơ sở dữ liệu ở một nơi khác (chẳng hạn như hệ thống con dịch vụ riêng biệt), và hơn thế nữa, thay vì xen kẽ các mối quan tâm hệ thống khác nhau trong cùng một thành phần. [11]

Hỗ trợ tách mối quan tâm chính cải thiện sự ghép nối và sự gắn kết trong thiết kế. Vì vậy, mặc dù bởi Expert chúng ta có thể tìm thấy một số lý do để đặt trách nhiệm cho các dịch vụ cơ sở dữ liệu trong lớp Sale, vì những lý do khác (thường là sự gắn kết và ghép nối), chúng ta sẽ kết thúc với một thiết kế kém.

Do đó SRP thường vượt trội hơn Chuyên gia thông tin.

Tuy nhiên, Nguyên tắc đảo ngược phụ thuộc có thể kết hợp tốt với chuyên gia. Các đối số ở đây sẽ là khách hàng không nên có một sự phụ thuộc của CustomerDTO (nói chung để chi tiết), nhưng cách khác xung quanh. Điều này có nghĩa rằng CustomerDTO là chuyên gia và cần biết làm thế nào để xây dựng bản thân cho một khách hàng:

CustomerDTO dto = new CustomerDTO(bob); 

Nếu bạn bị dị ứng với mới, bạn có thể đi tĩnh:

CustomerDTO dto = CustomerDTO.buildFor(bob); 

Hoặc, nếu bạn ghét cả hai, chúng tôi quay lại với AbstractFactory:

public abstract class DTOFactory<D, E> { 
    public abstract D createDTO(E entity); 
} 


public class CustomerDTOFactory extends DTOFactory<CustomerDTO, Customer> { 
    @Override 
    public CustomerDTO createDTO(Customer entity) { 
     return new CustomerDTO(entity); 
    } 
} 
Các vấn đề liên quan