Tôi có sai khi nghĩ rằng cần một cái gì đó như AutoMapper là một dấu hiệu của thiết kế kém?


35

Automapper là một "trình ánh xạ đối tượng đối tượng" cho .Net, có nghĩa là sao chép các đối tượng từ một lớp sang một lớp khác đại diện cho cùng một điều.

Tại sao điều này bao giờ hữu ích? Là sự trùng lặp của các lớp bao giờ hữu ích / thiết kế tốt?


Một tham khảo nhỏ: devtrends.co.uk/blog/ Mạnh Đặc biệt đọc phần "tại sao chúng ta không thể sử dụng máy tự động?"
Jani Hyytiäinen

Câu trả lời:


28

Một tìm kiếm nhanh trên google đã tiết lộ ví dụ này:

http://www.codeproject.com/Articles/61629/AutoMapper

hiển thị cách sử dụng AutoMapper hoàn toàn hợp lệ, đây chắc chắn không phải là một ví dụ cho thiết kế kém. Trong một ứng dụng được xếp lớp, bạn có thể có các đối tượng trong lớp dữ liệu hoặc lớp nghiệp vụ của mình và đôi khi bạn chỉ cần một tập hợp con các thuộc tính của các đối tượng dữ liệu đó hoặc một dạng xem nào đó trong lớp UI của bạn. Vì vậy, bạn tạo một mô hình khung nhìn chứa các đối tượng với chính xác các thuộc tính bạn cần trong giao diện người dùng của bạn, chứ không phải nhiều hơn và sử dụng AutoMapper để cung cấp nội dung của các đối tượng đó với mã nồi hơi ít hơn.

Trong tình huống như vậy, "đối tượng xem" của bạn không phải là bản sao của lớp gốc. Chúng có các phương thức khác nhau và có lẽ một vài thuộc tính trùng lặp. Nhưng điều đó cũng được miễn là bạn chỉ sử dụng các đối tượng xem đó cho mục đích hiển thị UI và không bắt đầu lạm dụng chúng để thao tác dữ liệu hoặc hoạt động kinh doanh.

Một chủ đề khác mà bạn có thể đọc để hiểu rõ hơn về vấn đề này là mẫu Phân chia trách nhiệm truy vấn lệnh của Fowlers , trái ngược với CRUD. Nó cho bạn thấy các tình huống trong đó các mô hình đối tượng khác nhau để truy vấn dữ liệu và cập nhật chúng trong cơ sở dữ liệu có ý nghĩa. Ở đây, ánh xạ từ mô hình đối tượng này sang mô hình đối tượng khác cũng có thể được thực hiện bởi một công cụ như AutoMapper.


1
Về ví dụ đầu tiên của bạn: bạn không thể sáng tác các đối tượng thay vì sao chép chúng? Trong trường hợp đó, các đối tượng UI của bạn sẽ có một tham chiếu đến các đối tượng dữ liệu ban đầu của bạn và sẽ chỉ hiển thị các yếu tố cần thiết. Điều đó có hợp lý không?
static_rtti

1
@static_rtti trên lý thuyết là có, nhưng bạn có thể không nhất thiết muốn lớp ban đầu của mình được công khai hoặc / và được hiển thị trong một hội đồng
Jalayn

2
@static_rtti: vâng, đó là một cách tiếp cận hoàn toàn hợp lệ, khác biệt. Sự khác biệt chính giữa hai thiết kế đó là thời gian tồn tại của dữ liệu / thuộc tính. Sử dụng các bản sao cung cấp cho bạn một ảnh chụp nhanh của dữ liệu, sử dụng các thuộc tính tham chiếu dữ liệu gốc thì không. Cả hai phương pháp đều có ưu và nhược điểm, nhưng nói chung IMHO không có "tốt hơn hay xấu hơn". Ngoài ra, có thể có những cân nhắc về hiệu suất, có thể có hoặc không ảnh hưởng đến quyết định sử dụng cái gì.
Doc Brown

3
Tách càng nhiều càng tốt luôn là một ý tưởng tốt. Không phải vì nó đặc biệt có lợi cho các dự án nhỏ, mà vì các dự án phát triển.
Tamás Szelei

6
@fish: Tôi đồng ý chủ yếu, tách rời thường là một ý tưởng tốt, nhưng IMHO có đủ các tình huống để giữ cho mọi thứ đơn giản vượt trội hơn so với cách tiếp cận tách lớp nhiều lớp. Phần khó là không bỏ lỡ điểm trong quá trình tăng trưởng của dự án khi người ta nên bắt đầu tái cấu trúc.
Doc Brown

45

Là sự trùng lặp của các lớp bao giờ hữu ích / thiết kế tốt?

Thực hành tốt của nó là có một lớp mô hình khung nhìn riêng biệt để sử dụng trong lớp UI thay vì sử dụng cùng một lớp được sử dụng trong lớp dữ liệu. Giao diện người dùng / trang web của bạn có thể cần hiển thị các bit thông tin khác không liên quan chặt chẽ đến thực thể dữ liệu. Bằng cách tạo lớp bổ sung này, bạn có thể tự do điều chỉnh giao diện người dùng của mình một cách dễ dàng khi các yêu cầu thay đổi theo thời gian.

Theo như sử dụng AutoMapper, cá nhân tôi tránh nó vì 3 lý do:

Thất bại im lặng phổ biến hơn

Vì AutoMapper ánh xạ giữa các thuộc tính một cách tự động, việc thay đổi tên thuộc tính trên một lớp chứ không phải lớp kia sẽ khiến ánh xạ thuộc tính bị bỏ qua. Trình biên dịch sẽ không biết. Automapper sẽ không quan tâm.

Thiếu phân tích tĩnh

Vì vậy, bạn đã được cung cấp một cơ sở mã lớn để đối phó. Có một triệu lớp với một triệu thuộc tính. Rất giống như chúng không được sử dụng, hoặc là bản sao. Công cụ "Tìm tất cả tài liệu tham khảo" trong Visual Studio sẽ giúp bạn xem các thuộc tính được sử dụng và giúp xây dựng bản đồ trong đầu về cách toàn bộ ứng dụng kết hợp với nhau. Nhưng chờ đã, không có tài liệu tham khảo rõ ràng nào cho một nửa các thuộc tính vì Automapper đang được sử dụng. Công việc của tôi bây giờ là một địa ngục khó khăn hơn nhiều.

Yêu cầu muộn làm tăng sự phức tạp

Automapper hoàn toàn ổn và bảnh bao khi tất cả những gì bạn muốn làm là sao chép các giá trị từ lớp này sang lớp khác (như trường hợp BẮT ĐẦU của sự phát triển), nhưng bạn có nhớ những yêu cầu đó thay đổi theo thời gian không? Điều gì xảy ra nếu bây giờ bạn cần nhận các giá trị từ các phần khác trong ứng dụng của mình, có lẽ cụ thể đối với người dùng đã đăng nhập hoặc một số trạng thái theo ngữ cảnh khác?

Mô hình của AutoMapper trong việc tạo ánh xạ một lớp một khi bắt đầu ứng dụng không cho vay chính xác các loại thay đổi theo ngữ cảnh cụ thể này. Vâng, có lẽ có cách để làm cho nó hoạt động, nhưng tôi thường thấy nó sạch hơn, đơn giản hơn và biểu cảm hơn để tự viết logic.

Tóm lại, trước khi tiếp cận Automapper để tiết kiệm cho mình 30 giây ánh xạ thủ công lớp này sang lớp khác, hãy nghĩ về điều này.

Lập trình là nghệ thuật nói cho một người khác biết người ta muốn máy tính làm gì. - Donald Knuth

Với suy nghĩ này, hãy tự hỏi mình "AutoMapper có hữu ích hôm nay không và nó có phải là ngày mai không?"


[nếu bạn làm nhà phát triển web hợp thời trang] Vì vậy, nếu bạn đang viết một dịch vụ web REST, bạn có xu hướng luôn kiểm tra từng thuộc tính để đảm bảo mô hình đối tượng JavaScript của bạn phù hợp với mô hình đối tượng .NET của bạn không?
Den

3
@Den - vâng. Và bạn viết các bài kiểm tra để đảm bảo bạn nhận được tất cả các thuộc tính chính xác (ví dụ: bài kiểm tra của bạn sẽ hiển thị bất kỳ thuộc tính nào bạn đã thêm vào 1 vị trí không được truyền đến các tầng khác)
gbjbaanb

@gbjbaanb Tôi có lẽ chỉ cần sử dụng sự phản chiếu để thực hiện xác nhận này một cách chung chung. Có lẽ khám phá khả năng mở rộng AutoMapper để thêm một số xác nhận. Chắc chắn sẽ tránh được rất nhiều bài tập thủ công.
Den

Hoàn toàn đồng ý với bạn và nghĩ rằng chỉ những ứng dụng rất đơn giản mới có thể sử dụng automapper, nhưng khi mọi thứ trở nên phức tạp hơn, chúng ta cần phải viết cấu hình mới cho automapper thì tại sao không viết chúng trong một trình trợ giúp hoặc dịch vụ ánh xạ thủ công.
ahmedsafan86

21

Theo kinh nghiệm của tôi, khi ai đó phàn nàn về 'quá nhiều nồi hơi' và muốn sử dụng AutoMapper, đó là một trong những điều sau đây:

  1. Họ cảm thấy khó chịu khi viết cùng một mã nhiều lần.
  2. Họ lười biếng và không muốn viết mã mà Ax = Bx
  3. Họ phải chịu quá nhiều áp lực thời gian để thực sự nghĩ về việc viết Ax = Bx nhiều lần có phải là một ý tưởng hay không và sau đó viết mã tốt cho nhiệm vụ.

Tuy nhiên:

  1. Nếu đó thực sự là về việc tránh lặp lại, bạn có thể tạo một đối tượng hoặc phương thức để trừu tượng hóa nó. Bạn không cần AutoMapper.
  2. Nếu bạn lười biếng, bạn sẽ lười biếng và sẽ không học cách AutoMapper hoạt động. Thay vào đó, bạn sẽ áp dụng mô hình 'lập trình theo sự trùng hợp' và viết mã khủng khiếp trong đó bạn đưa logic kinh doanh vào hồ sơ AutoMapper. Trong trường hợp này, bạn nên thay đổi thái độ của mình đối với lập trình hoặc tìm việc khác để làm nghề. Bạn không cần AutoMapper.
  3. Nếu bạn chịu quá nhiều áp lực thời gian, vấn đề của bạn không liên quan gì đến việc lập trình. Bạn không cần AutoMapper.

Nếu bạn đã chọn một ngôn ngữ được nhập tĩnh, thì hãy tận dụng ngôn ngữ đó. Nếu bạn đang cố gắng phá vỡ các điều khiển bằng ngôn ngữ giúp ngăn ngừa lỗi do sử dụng quá nhiều API phản chiếu và ma thuật như AutoMapper, điều đó có nghĩa là bạn đã chọn một ngôn ngữ không thỏa mãn cho nhu cầu của bạn.

Ngoài ra, chỉ vì Microsoft thêm các tính năng vào C # không có nghĩa là chúng là trò chơi công bằng trong mọi tình huống hoặc chúng hỗ trợ thực tiễn tốt nhất. Chẳng hạn, sự phản chiếu và từ khóa 'động' nên được sử dụng trong trường hợp bạn đơn giản không thể hoàn thành những gì bạn cần mà không có chúng. AutoMapper không phải là giải pháp cho mọi trường hợp sử dụng mà không thể giải quyết được nếu không có nó.

Vì vậy, là sự trùng lặp của các lớp thiết kế xấu? Không cần thiết.

AutoMapper là một ý tưởng tồi? Phải, chắc chắn rồi.

Việc sử dụng AutoMapper cho thấy sự thiếu hụt hệ thống trong dự án. Nếu bạn thấy mình cần nó, hãy dừng lại và suy nghĩ về thiết kế của bạn. Bạn sẽ luôn tìm thấy một thiết kế tốt hơn, dễ đọc hơn, dễ bảo trì hơn và không có lỗi hơn.


1
Nói tốt, đặc biệt là 2.
Mardoxx

2
Tôi biết rằng đây là chủ đề rất cũ, nhưng tôi không đồng ý với 1. Bạn không thể tạo một phương thức để ánh xạ trừu tượng. Bạn có thể cho 1 lớp, nhưng nếu có 2, bạn cần 2 phương thức. 3 - 3 phương pháp. Với AM đây là 1 dòng mã - định nghĩa ánh xạ. Thêm vào đó, tôi thực sự vật lộn với một kịch bản, trong đó tôi có Danh sách <BaseType> chứa 10 kiểu con DTO. Khi bạn muốn ánh xạ điều đó, bạn cần một công tắc trên loại VÀ một phương thức để sao chép các giá trị trường. Và nếu một trong các trường phải được ánh xạ riêng biệt thì sao? Câu trả lời của bạn chỉ tốt nếu bạn có một vài lớp học đơn giản. AutoMapper chiến thắng trong các tình huống phức tạp hơn.
dùng3512524

1
(giới hạn char) Cạm bẫy duy nhất của AM tôi nghĩ là khả năng thay đổi tên của tài sản trong một lớp chứ không phải trong lớp khác. Nhưng thực sự, bạn có thường xuyên làm điều đó sau khi thiết kế được thực hiện? Và bạn có thể viết một phương thức kiểm tra chung sử dụng sự phản chiếu và so sánh các tên thuộc tính. Giống như tất cả các công cụ, AM phải được sử dụng một cách chính xác - không mù quáng, không phải trong mọi tình huống, tôi đồng ý. Nhưng nói "bạn không nên sử dụng nó" là sai.
dùng3512524

7

Có một vấn đề sâu sắc hơn ở đây: thực tế là C # và Java nhấn mạnh hầu hết / tất cả các loại phải được phân biệt bằng tên chứ không phải cấu trúc: ví dụ class MyPoint2Dclass YourPoint2Dlà các loại riêng biệt ngay cả khi chúng có cùng định nghĩa chính xác. Khi loại bạn muốn là "một số thứ ẩn danh với một xtrường và một ytrường" (tức là một bản ghi ), bạn đã hết may mắn. Vì vậy, khi bạn muốn biến a YourPoint2Dthành a MyPoint2D, bạn có ba tùy chọn:

  1. Viết một số bản tóm tắt tẻ nhạt, lặp đi lặp lại, trần tục dọc theo dòng this.x = that.x; this.y = that.y
  2. Tạo mã bằng cách nào đó.
  3. Sử dụng phản xạ.

Lựa chọn 1 là đủ dễ dàng với liều lượng nhỏ nhưng nhanh chóng trở thành một việc vặt khi số lượng loại bạn cần lập bản đồ là lớn.

Lựa chọn 2 ít hơn mong muốn vì bây giờ bạn phải thêm một bước nữa vào quy trình xây dựng của mình để tạo mã và đảm bảo toàn bộ nhóm có được bản ghi nhớ. Trong trường hợp xấu nhất, bạn cũng phải cuộn trình tạo mã hoặc hệ thống mẫu của riêng mình.

Điều đó để lại cho bạn sự phản ánh. Bạn có thể tự làm điều đó hoặc bạn có thể sử dụng AutoMapper.


2

Automapper là một trong những thư viện / công cụ mà hoàng đế thực sự đang chạy quanh mông trần. Khi bạn vượt qua logo hào nhoáng, bạn nhận ra nó không làm bất cứ điều gì bạn không thể làm thủ công với kết quả tốt hơn nhiều.

Mặc dù tôi không hoàn toàn chắc chắn làm thế nào nó gợi ý cho các thành viên lập bản đồ tự động, nhưng rất có thể nó liên quan đến logic thời gian chạy bổ sung và khả năng phản chiếu có thể. Đây có thể là một hình phạt hiệu suất đáng kể để đổi lấy một khoản tiết kiệm thời gian. Mặt khác, ánh xạ thủ công được thực hiện tốt trước khi biên dịch thời gian.

Trong trường hợp AutoMapper không có đầu mối, bạn phải định cấu hình ánh xạ với mã và cài đặt cờ. Nếu bạn sẽ bận tâm thực hiện tất cả các công việc thiết lập và mã, bạn phải đặt câu hỏi nó tiết kiệm được bao nhiêu so với ánh xạ thủ công.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.