Tôi có phá vỡ thực hành OOP với kiến ​​trúc này không?


23

Tôi có một ứng dụng web. Tôi không tin công nghệ là quan trọng. Cấu trúc là một ứng dụng N-tier, được hiển thị trong hình bên trái. Có 3 lớp.

UI (mẫu MVC), Lớp logic nghiệp vụ (BLL) và Lớp truy cập dữ liệu (DAL)

Vấn đề tôi gặp phải là BLL của tôi rất lớn vì nó có logic và đường dẫn thông qua các sự kiện ứng dụng gọi.

Một luồng thông thường thông qua ứng dụng có thể là:

Sự kiện được kích hoạt trong UI, đi qua một phương thức trong BLL, thực hiện logic (có thể ở nhiều phần của BLL), cuối cùng đến DAL, trở lại BLL (nơi có khả năng logic hơn) và sau đó trả lại một số giá trị cho UI.

BLL trong ví dụ này rất bận rộn và tôi đang nghĩ làm thế nào để tách nó ra. Tôi cũng có logic và các đối tượng kết hợp mà tôi không thích.

nhập mô tả hình ảnh ở đây

Phiên bản bên phải là nỗ lực của tôi.

Logic vẫn là cách ứng dụng chảy giữa UI và DAL, nhưng có thể không có thuộc tính ... Chỉ có các phương thức (phần lớn các lớp trong lớp này thể có thể tĩnh vì chúng không lưu trữ bất kỳ trạng thái nào). Lớp Poco là nơi các lớp tồn tại có các thuộc tính (chẳng hạn như lớp Person nơi sẽ có tên, tuổi, chiều cao, v.v.). Chúng sẽ không liên quan gì đến dòng chảy của ứng dụng, chúng chỉ lưu trữ trạng thái.

Dòng chảy có thể là:

Thậm chí được kích hoạt từ UI và chuyển một số dữ liệu tới bộ điều khiển lớp UI (MVC). Điều này chuyển dữ liệu thô và chuyển đổi nó thành mô hình poco. Mô hình poco sau đó được chuyển vào lớp Logic (là BLL) và cuối cùng đến lớp truy vấn lệnh, có khả năng bị thao túng trên đường đi. Lớp truy vấn lệnh chuyển đổi POCO thành một đối tượng cơ sở dữ liệu (gần giống nhau, nhưng một lớp được thiết kế để duy trì, lớp kia cho giao diện người dùng). Mục này được lưu trữ và một đối tượng cơ sở dữ liệu được trả về lớp Truy vấn lệnh. Sau đó, nó được chuyển đổi thành POCO, nơi nó trở lại lớp Logic, có khả năng được xử lý thêm và cuối cùng, trở lại giao diện người dùng

Các logic và giao diện được chia sẻ là nơi chúng ta có thể có dữ liệu liên tục, chẳng hạn như MaxNumberOf_X và Total ALLowed_X và tất cả các giao diện.

Cả logic / giao diện được chia sẻ và DAL đều là "cơ sở" của kiến ​​trúc. Những điều này không biết gì về thế giới bên ngoài.

Mọi thứ đều biết về poco ngoài logic / giao diện và DAL được chia sẻ.

Luồng vẫn rất giống với ví dụ đầu tiên, nhưng nó làm cho mỗi lớp có trách nhiệm hơn đối với 1 điều (có thể là trạng thái, luồng hoặc bất cứ điều gì khác) ... nhưng tôi có phá vỡ OOP bằng phương pháp này không?

Một ví dụ để demo Logic và Poco có thể là:

public class LogicClass
{
    private ICommandQueryObject cmdQuery;
    public PocoA Method1(PocoB pocoB) 
    { 
        return cmdQuery.Save(pocoB); 
    }

    /*This has no state objects, only ways to communicate with other 
    layers such as the cmdQuery. Everything else is just function 
    calls to allow flow via the program */
    public PocoA Method2(PocoB pocoB) 
    {         
        pocoB.UpdateState("world"); 
        return Method1(pocoB);
    }

}

public struct PocoX
{
     public string DataA {get;set;}
     public int DataB {get;set;}
     public int DataC {get;set;}

    /*This simply returns something that is part of this class. 
     Everything is self-contained to this class. It doesn't call 
     trying to directly communicate with databases etc*/
     public int GetValue()
     {

         return DataB * DataC; 
     }

     /*This simply sets something that is part of this class. 
     Everything is self-contained to this class. 
     It doesn't call trying to directly communicate with databases etc*/
     public void UpdateState(string input)
     {        
         DataA += input;  
     }
}

Tôi không thấy bất cứ điều gì sai về cơ bản với kiến ​​trúc của bạn như bạn hiện đang mô tả nó.
Robert Harvey

19
Không có đủ chi tiết chức năng trong ví dụ mã của bạn để cung cấp thêm thông tin chi tiết. Ví dụ Foobar hiếm khi cung cấp đủ minh họa.
Robert Harvey


4
Chúng ta có thể tìm thấy một tiêu đề tốt hơn cho câu hỏi này để nó có thể được tìm thấy trực tuyến dễ dàng hơn không?
Soner Gönül

1
Chỉ là phạm vi: một lớp và một lớp không giống nhau. Một "lớp" nói về việc triển khai, một "lớp" về logic. Lớp dữ liệu của bạn sẽ được triển khai cho cả tầng mã máy chủ và cơ sở dữ liệu. Lớp UI của bạn sẽ được triển khai cho cả tầng mã máy khách và máy chủ phía máy chủ. Kiến trúc bạn hiển thị là kiến ​​trúc 3 lớp. Các bậc của bạn là "Máy khách Web", "Mã phía máy chủ" và "Cơ sở dữ liệu".
Laurent LA RIZZA

Câu trả lời:


54

Có, bạn rất có thể phá vỡ các khái niệm OOP cốt lõi . Tuy nhiên, đừng cảm thấy tồi tệ, mọi người làm điều này mọi lúc, điều đó không có nghĩa là kiến ​​trúc của bạn "sai". Tôi có thể nói rằng nó có thể ít được bảo trì hơn một thiết kế OO thích hợp, nhưng điều này khá chủ quan và không phải là câu hỏi của bạn. ( Đây là một bài viết của tôi chỉ trích kiến ​​trúc n-tier nói chung).

Lý do : Khái niệm cơ bản nhất của OOP là dữ liệu và logic tạo thành một đơn vị (một đối tượng). Mặc dù đây là một tuyên bố rất đơn giản và máy móc, ngay cả như vậy, nó không thực sự được tuân theo trong thiết kế của bạn (nếu tôi hiểu bạn chính xác). Bạn khá rõ ràng tách hầu hết dữ liệu khỏi hầu hết logic. Ví dụ, có các phương thức không trạng thái (giống như tĩnh) được gọi là "thủ tục" và thường phản đối với OOP.

Tất nhiên luôn có ngoại lệ, nhưng thiết kế này vi phạm những điều này như một quy tắc.

Một lần nữa, tôi muốn nhấn mạnh "vi phạm OOP"! = "Sai", vì vậy đây không nhất thiết là một đánh giá giá trị. Tất cả phụ thuộc vào các ràng buộc kiến ​​trúc của bạn, các trường hợp sử dụng bảo trì, các yêu cầu, v.v.


9
Có một upvote, đây là một câu trả lời tốt, nếu tôi tự viết, tôi sẽ sao chép và dán nó, nhưng cũng thêm rằng, nếu bạn thấy bản thân mình không viết mã OOP, có lẽ bạn nên xem xét một ngôn ngữ không phải OOP như nó đi kèm với rất nhiều chi phí bổ sung mà bạn có thể làm mà không cần sử dụng
TheCatWhisperer

2
@TheCatWhisperer: Kiến trúc doanh nghiệp hiện đại không vứt bỏ hoàn toàn OOP, chỉ chọn lọc (ví dụ: đối với DTO).
Robert Harvey

@RobertHarvey Đồng ý, ý tôi là nếu bạn không sử dụng OOP ở bất cứ đâu trong thiết kế của bạn
TheCatWhisperer

@TheCatWhisperer nhiều ưu điểm trong một oop như c # không nhất thiết phải ở phần oop của ngôn ngữ mà là hỗ trợ có sẵn như thư viện, phòng thu trực quan, quản lý bộ nhớ, v.v.

@Orangesandlemons Tôi chắc chắn có rất nhiều ngôn ngữ được hỗ trợ tốt khác ...
TheCatWhisperer

31

Một trong những nguyên tắc cốt lõi của Lập trình hàm là các hàm thuần túy.

Một trong những nguyên tắc cốt lõi của Lập trình hướng đối tượng là đặt các chức năng cùng với dữ liệu họ hành động.

Cả hai nguyên tắc cốt lõi này đều biến mất khi ứng dụng của bạn phải giao tiếp với thế giới bên ngoài. Thật vậy, bạn chỉ có thể đúng với những lý tưởng này trong một không gian được chuẩn bị đặc biệt trong hệ thống của bạn. Không phải mọi dòng mã của bạn phải đáp ứng những lý tưởng này. Nhưng nếu không có dòng mã nào của bạn đáp ứng những lý tưởng này, bạn thực sự không thể yêu cầu sử dụng OOP hoặc FP.

Vì vậy, sẽ ổn khi chỉ có các "đối tượng" dữ liệu mà bạn chạy xung quanh vì bạn cần chúng để vượt qua một ranh giới mà bạn chỉ đơn giản là không thể cấu trúc lại để di chuyển mã quan tâm. Chỉ cần biết rằng đó không phải là OOP. Đó là thực tế. OOP là khi, một khi bên trong ranh giới đó, bạn tập hợp tất cả logic hoạt động trên dữ liệu đó vào một nơi.

Không phải là bạn phải làm điều đó. OOP không phải là tất cả mọi thứ cho tất cả mọi người. Đó là những gì nó được. Chỉ không yêu cầu một cái gì đó theo OOP khi nó không hoặc bạn sẽ nhầm lẫn mọi người đang cố gắng duy trì mã của bạn.

POCO của bạn dường như có logic kinh doanh tốt, vì vậy tôi sẽ không lo lắng quá nhiều về việc bị thiếu máu. Điều làm tôi lo lắng là tất cả đều có vẻ rất đột biến. Hãy nhớ rằng getters và setters không cung cấp đóng gói thực sự. Nếu POCO của bạn đang hướng đến ràng buộc đó thì tốt. Chỉ cần hiểu điều này không mang lại cho bạn đầy đủ lợi ích của một đối tượng OOP được đóng gói thực sự. Một số người gọi đây là Đối tượng truyền dữ liệu hoặc DTO.

Một mẹo tôi đã sử dụng thành công là tạo các đối tượng OOP ăn ​​DTO. Tôi sử dụng DTO làm đối tượng tham số . Nhà xây dựng của tôi đọc trạng thái từ nó (đọc là bản sao phòng thủ ) và ném nó sang một bên. Bây giờ tôi đã có một phiên bản DTO được đóng gói đầy đủ và không thay đổi. Tất cả các phương pháp liên quan đến dữ liệu này có thể được chuyển đến đây với điều kiện chúng ở bên này của ranh giới đó.

Tôi không cung cấp getters hoặc setters. Tôi làm theo , đừng hỏi . Bạn gọi phương pháp của tôi và họ đi làm những gì cần làm. Họ có thể thậm chí không cho bạn biết những gì họ đã làm. Họ chỉ làm điều đó.

Bây giờ cuối cùng một cái gì đó, một nơi nào đó sẽ chạy vào một ranh giới khác và tất cả điều này lại sụp đổ một lần nữa. Đó là tốt. Xoay một DTO khác và ném nó lên tường.

Đây là bản chất của kiến ​​trúc cổng và bộ điều hợp. Tôi đã đọc về nó từ góc độ chức năng . Có lẽ nó cũng sẽ khiến bạn quan tâm.


5
" Getters và setters không cung cấp đóng gói thực sự " - có!
Boris the Spider

3
@BoristheSpider - getters và setters hoàn toàn cung cấp đóng gói, chúng chỉ không phù hợp với định nghĩa hẹp của bạn về đóng gói.
Davor dralo

4
@ DavorŽdralo: Đôi khi chúng hữu ích như một cách giải quyết, nhưng do bản chất của chúng, getters và setters phá vỡ đóng gói. Cung cấp một cách để có được và thiết lập một số biến nội bộ ngược lại với trách nhiệm đối với trạng thái của chính bạn và hành động theo nó.
cHao

5
@cHao - bạn không hiểu getter là gì. Nó không có nghĩa là một phương thức trả về giá trị của một thuộc tính đối tượng. Đó là một triển khai phổ biến, nhưng nó có thể trả về một giá trị từ cơ sở dữ liệu, yêu cầu nó qua http, tính toán nó một cách nhanh chóng, bất cứ điều gì. Giống như tôi đã nói, getters và setters chỉ phá vỡ đóng gói khi mọi người sử dụng định nghĩa hẹp (và không chính xác) của riêng họ.
Davor dralo

4
@cHao - đóng gói có nghĩa là bạn đang ẩn thực hiện. Đó là những gì được gói gọn. Nếu bạn có getter "getSurfaceArea ()" trên một lớp Square, bạn không biết liệu diện tích bề mặt có phải là một trường hay không, nếu nó được tính khi đang bay (chiều cao trở lại * chiều rộng) hoặc một số phương thức thứ ba, vì vậy bạn có thể thay đổi triển khai bên trong bất cứ lúc nào bạn thích, bởi vì nó được gói gọn.
Davor dralo

1

Nếu tôi đọc chính xác lời giải thích của bạn, các đối tượng của bạn trông hơi giống thế này: (khó khăn không có ngữ cảnh)

public class LogicClass
{
    private ICommandQueryObject cmdQuery;
    public PocoA Method(PocoB pocoB) { ... }
}

public class PocoX
{
     public string DataA {get;set;}
     public int DataB {get;set;}
     ... etc
}

Trong đó các lớp Poco của bạn chỉ chứa dữ liệu và các lớp Logic của bạn chứa các phương thức hành động trên dữ liệu đó; vâng, bạn đã phá vỡ các nguyên tắc của "Classic OOP"

Một lần nữa, thật khó để nói từ mô tả khái quát của bạn, nhưng tôi sẽ nguy hiểm rằng những gì bạn đã viết có thể được phân loại là Mô hình miền thiếu máu.

Tôi không nghĩ rằng đây là một cách tiếp cận đặc biệt xấu, cũng như, nếu bạn coi Poco của bạn là những cấu trúc thì nó sẽ phá vỡ OOP theo nghĩa cụ thể hơn. Trong đó Đối tượng của bạn bây giờ là LogicClass. Thật vậy, nếu bạn làm cho chiếc xe của bạn trở nên bất biến, thiết kế có thể được coi là khá Chức năng.

Tuy nhiên, khi bạn tham khảo Shared Logic, Pocos gần như không giống nhau và thống kê tôi bắt đầu lo lắng về chi tiết thiết kế của bạn.


Tôi đã thêm vào bài viết của mình, về cơ bản là sao chép ví dụ của bạn. Xin lỗi vì không rõ ràng để bắt đầu với
MyDaftQuestions

1
Ý tôi là, nếu bạn nói với chúng tôi ứng dụng nào thì việc viết ví dụ sẽ dễ dàng hơn. Thay vì LogicClass, bạn có thể có PaymentProvider hoặc bất cứ điều gì
Ewan

1

Một vấn đề tiềm ẩn mà tôi thấy trong thiết kế của bạn (và nó rất phổ biến) - một số mã "OO" hoàn toàn tồi tệ nhất tôi từng gặp là do một kiến ​​trúc tách các đối tượng "Dữ liệu" khỏi các đối tượng "Mã". Đây là thứ cấp độ ác mộng! Vấn đề là ở mọi nơi trong mã doanh nghiệp của bạn khi bạn muốn truy cập vào các đối tượng dữ liệu của mình, bạn CHỈ ĐẾN mã đó ngay tại đó (Bạn không phải, bạn có thể xây dựng một lớp tiện ích hoặc một chức năng khác để xử lý nó nhưng đây là những gì Tôi đã thấy xảy ra liên tục theo thời gian).

Mã truy cập / cập nhật thường không được thu thập để bạn kết thúc với chức năng trùng lặp ở mọi nơi.

Mặt khác, các đối tượng dữ liệu đó là hữu ích, ví dụ như sự tồn tại của cơ sở dữ liệu. Tôi đã thử ba giải pháp:

Sao chép các giá trị vào và ra đối tượng "thực" và vứt bỏ đối tượng dữ liệu của bạn là tẻ nhạt (nhưng có thể là một giải pháp hợp lệ nếu bạn muốn đi theo cách đó).

Thêm các phương thức sắp xếp dữ liệu vào các đối tượng dữ liệu có thể hoạt động nhưng nó có thể tạo ra một đối tượng dữ liệu lộn xộn lớn đang làm nhiều việc. Nó cũng có thể làm cho việc đóng gói trở nên khó khăn hơn vì nhiều cơ chế kiên trì muốn người truy cập công cộng ... Tôi không thích nó khi tôi đã thực hiện nhưng đó là một giải pháp hợp lệ

Giải pháp phù hợp nhất với tôi là khái niệm về lớp "Wrapper" đóng gói lớp "Dữ liệu" và chứa tất cả chức năng sắp xếp dữ liệu - sau đó tôi hoàn toàn không hiển thị lớp dữ liệu (Thậm chí không phải là setters và getters trừ khi chúng thực sự cần thiết). Điều này loại bỏ sự cám dỗ để thao túng đối tượng trực tiếp và buộc bạn phải thêm chức năng chia sẻ vào trình bao bọc thay thế.

Ưu điểm khác là bạn có thể đảm bảo rằng lớp dữ liệu của bạn luôn ở trạng thái hợp lệ. Đây là một ví dụ nhanh về psuedocode:

// Data Class
Class User {
    String name;
    Date birthday;
}

Class UserHolder {
    final private User myUser // Cannot be null or invalid

    // Quickly wrap an object after getting it from the DB
    public UserHolder(User me)
    {
        if(me == null ||me.name == null || me.age < 0)
            throw Exception
        myUser=me
    }

    // Create a new instance in code
    public UserHolder(String name, Date birthday) {
        User me=new User()
        me.name=name
        me.birthday=birthday        
        this(me)
    }
    // Methods access attributes, they try not to return them directly.
    public boolean canDrink(State state) {
        return myUser.birthday.year < Date.yearsAgo(state.drinkingAge) 
    }
}

Lưu ý rằng bạn không có kiểm tra độ tuổi trải đều trong mã của mình ở các khu vực khác nhau và bạn cũng không muốn sử dụng nó bởi vì bạn thậm chí không thể biết ngày sinh nhật là gì (trừ khi bạn cần nó cho thứ khác, trong trường hợp nào bạn có thể thêm nó).

Tôi có xu hướng không chỉ mở rộng đối tượng dữ liệu vì bạn mất đóng gói này và đảm bảo an toàn - tại thời điểm đó, bạn cũng có thể chỉ cần thêm các phương thức vào lớp dữ liệu.

Bằng cách đó, logic nghiệp vụ của bạn không có một loạt các rác / vòng lặp truy cập dữ liệu lan truyền khắp nó, nó sẽ trở nên dễ đọc hơn và ít dư thừa hơn. Tôi cũng khuyên bạn nên tập thói quen luôn gói các bộ sưu tập vì cùng một lý do - giữ các cấu trúc lặp / tìm kiếm ngoài logic kinh doanh của bạn và đảm bảo chúng luôn ở trạng thái tốt.


1

Không bao giờ thay đổi mã của bạn bởi vì bạn nghĩ hoặc ai đó nói với bạn rằng đó không phải là cái này hay không. Thay đổi mã của bạn nếu nó mang lại cho bạn các vấn đề và bạn đã tìm ra cách để tránh những vấn đề này mà không tạo ra các vấn đề khác.

Vì vậy, ngoài việc bạn không thích mọi thứ, bạn muốn đầu tư nhiều thời gian để tạo ra sự thay đổi. Viết ra những vấn đề bạn có ngay bây giờ. Viết ra cách thiết kế mới của bạn sẽ giải quyết các vấn đề. Chỉ ra giá trị của sự cải thiện và chi phí thực hiện các thay đổi của bạn. Sau đó - và điều này là quan trọng nhất - đảm bảo rằng bạn có thời gian để hoàn thành những thay đổi đó, hoặc bạn sẽ kết thúc một nửa ở trạng thái này, một nửa ở trạng thái đó và đó là tình huống tồi tệ nhất có thể. (Tôi đã từng làm việc trong một dự án với 13 loại chuỗi khác nhau và ba nỗ lực nửa vời có thể xác định để chuẩn hóa một loại)


0

Danh mục "OOP" lớn hơn và trừu tượng hơn nhiều so với những gì bạn đang mô tả. Nó không quan tâm đến tất cả những điều này. Nó quan tâm đến trách nhiệm rõ ràng, sự gắn kết, khớp nối. Vì vậy, ở cấp độ bạn đang hỏi, sẽ không có ý nghĩa gì khi hỏi về "thực hành OOPS".

Điều đó nói rằng, với ví dụ của bạn:

Dường như với tôi có một sự hiểu lầm về ý nghĩa của MVC. Bạn đang gọi UI của mình là "MVC", tách biệt với logic nghiệp vụ và điều khiển "phụ trợ". Nhưng đối với tôi, MVC bao gồm toàn bộ ứng dụng web:

  • Mô hình - chứa dữ liệu nghiệp vụ + logic
    • Lớp dữ liệu như chi tiết triển khai của mô hình
  • Xem - Mã UI, mẫu HTML, CSS, v.v.
    • Bao gồm các khía cạnh phía máy khách như JavaScript hoặc các thư viện cho các ứng dụng web "một trang", v.v.
  • Kiểm soát - keo phía máy chủ giữa tất cả các phần khác
  • (Có các tiện ích mở rộng như ViewModel, Batch, v.v. mà tôi sẽ không truy cập vào đây)

Có một số giả định cơ bản cực kỳ quan trọng ở đây:

  • Một lớp / đối tượng Mô hình không bao giờ có bất kỳ kiến thức nào về bất kỳ phần nào khác (Xem, Điều khiển, ...). Nó không bao giờ gọi cho họ, nó không giả sử được gọi bởi họ, nó không có thuộc tính / tham số sesssion hoặc bất cứ điều gì khác dọc theo dòng này. Nó hoàn toàn đơn độc. Trong các ngôn ngữ hỗ trợ điều này (ví dụ: Ruby), bạn có thể kích hoạt một dòng lệnh thủ công, khởi tạo các lớp Mô hình, làm việc với chúng theo nội dung trái tim của bạn và có thể làm mọi thứ chúng làm mà không cần bất kỳ trường hợp nào của Control hoặc View hoặc bất kỳ danh mục nào khác. Nó không có kiến ​​thức về phiên, người dùng, vv, quan trọng nhất.
  • Không có gì chạm vào lớp dữ liệu ngoại trừ thông qua một mô hình.
  • Khung nhìn chỉ chạm nhẹ vào mô hình (hiển thị nội dung, v.v.) và không có gì khác. (Lưu ý rằng một tiện ích mở rộng tốt là "ViewModel", đây là các lớp đặc biệt xử lý đáng kể hơn để hiển thị dữ liệu theo cách phức tạp, không phù hợp với Mô hình hoặc Chế độ xem - đây là một ứng cử viên tốt để xóa / tránh phình to trong Mô hình thuần túy).
  • Điều khiển càng nhẹ càng tốt, nhưng nó chịu trách nhiệm tập hợp tất cả những người chơi khác lại với nhau và chuyển nội dung xung quanh họ (nghĩa là trích xuất các mục nhập của người dùng từ một biểu mẫu và chuyển tiếp nó đến mô hình, chuyển các ngoại lệ từ logic nghiệp vụ sang hữu ích thông báo lỗi cho người dùng, vv). Đối với API Web / HTTP / REST, v.v., tất cả các ủy quyền, bảo mật, quản lý phiên, quản lý người dùng, v.v. đều xảy ra ở đây (và chỉ ở đây).

Điều quan trọng: UI là một phần của MVC. Không phải cách khác (như trong sơ đồ của bạn). Nếu bạn chấp nhận điều đó, thì những người mẫu béo thực sự khá giỏi - miễn là họ thực sự không chứa những thứ họ không nên.

Lưu ý rằng "mô hình chất béo" có nghĩa là tất cả logic nghiệp vụ nằm trong danh mục Mô hình (gói, mô-đun, bất kể tên trong ngôn ngữ bạn chọn là gì). Các lớp riêng lẻ rõ ràng phải được cấu trúc OOP theo cách tốt cho bất kỳ nguyên tắc mã hóa nào bạn tự đưa ra (ví dụ: một số dòng mã tối đa cho mỗi lớp hoặc mỗi phương thức, v.v.).

Cũng lưu ý rằng cách lớp dữ liệu được thực hiện có những hậu quả rất quan trọng; đặc biệt là liệu lớp mô hình có thể hoạt động mà không cần lớp dữ liệu (ví dụ: để kiểm tra đơn vị hoặc cho các DB trong bộ nhớ giá rẻ trên máy tính xách tay của nhà phát triển thay vì các DB DB đắt tiền hoặc bất cứ thứ gì bạn có). Nhưng đây thực sự là một chi tiết triển khai ở cấp độ kiến ​​trúc mà chúng ta đang xem xét ngay bây giờ. Rõ ràng ở đây bạn vẫn muốn có một sự tách biệt, tức là tôi sẽ không muốn thấy mã có logic miền thuần trực tiếp xen kẽ với truy cập dữ liệu, kết hợp chặt chẽ điều này với nhau. Một chủ đề cho một câu hỏi khác.

Để quay lại câu hỏi của bạn: Dường như với tôi có một sự chồng chéo lớn giữa kiến ​​trúc mới của bạn và sơ đồ MVC mà tôi đã mô tả, vì vậy bạn không đi sai hướng hoàn toàn, nhưng dường như bạn đang phát minh lại một số thứ, hoặc sử dụng nó bởi vì môi trường lập trình / thư viện hiện tại của bạn đề xuất như vậy. Khó để nói cho tôi. Vì vậy, tôi không thể cho bạn một câu trả lời chính xác về việc những gì bạn dự định là đặc biệt tốt hay xấu. Bạn có thể tìm hiểu bằng cách kiểm tra xem mỗi "điều" duy nhất có chính xác một lớp chịu trách nhiệm về nó hay không; cho dù mọi thứ đều gắn kết cao và kết hợp thấp. Điều đó mang lại cho bạn một dấu hiệu tốt, và theo tôi, là đủ cho một thiết kế OOP tốt (hoặc một điểm chuẩn tốt tương tự, nếu bạn muốn).

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.