Kết hợp phương pháp mẫu với chiến lược


14

Một nhiệm vụ trong lớp kỹ thuật phần mềm của tôi là thiết kế một ứng dụng có thể chơi các dạng khác nhau của một trò chơi cụ thể. Trò chơi trong câu hỏi là Mancala, một số trò chơi này được gọi là Wari hoặc Kalah. Các trò chơi này khác nhau ở một số khía cạnh nhưng đối với câu hỏi của tôi, điều quan trọng chỉ cần biết là các trò chơi có thể khác nhau như sau:

  • Cách xử lý kết quả của việc di chuyển
  • Cách xác định kết thúc trò chơi
  • Cách xác định người chiến thắng

Điều đầu tiên tôi nghĩ đến khi thiết kế nó là sử dụng mô hình chiến lược, tôi có một biến thể trong các thuật toán (quy tắc thực tế của trò chơi). Thiết kế có thể trông như thế này: nhập mô tả hình ảnh ở đây

Sau đó tôi tự nghĩ rằng trong trò chơi Mancala và Wari, cách người chiến thắng được xác định là hoàn toàn giống nhau và mã sẽ được sao chép. Tôi không nghĩ rằng điều này theo định nghĩa là vi phạm nguyên tắc 'một quy tắc, một nơi' hoặc DRY được coi là thay đổi quy tắc cho Mancala sẽ không tự động có nghĩa là quy tắc đó cũng nên được thay đổi trong Wari. Tuy nhiên, từ phản hồi tôi nhận được từ giáo sư của mình, tôi đã có ấn tượng để tìm một thiết kế khác.

Sau đó tôi đã nghĩ ra điều này: nhập mô tả hình ảnh ở đây

Mỗi trò chơi (Mancala, Wari, Kalah, ...) sẽ chỉ có thuộc tính loại giao diện của từng quy tắc, WinnerDeterminervà nếu có phiên bản Mancala 2.0 giống với Mancala 1.0 ngoại trừ cách xác định người chiến thắng thì có thể sử dụng các phiên bản Mancala.

Tôi nghĩ rằng việc thực hiện các quy tắc này như một mô hình chiến lược chắc chắn là hợp lệ. Nhưng vấn đề thực sự đến khi tôi muốn thiết kế nó hơn nữa.

Khi đọc về mẫu phương thức mẫu, tôi nghĩ ngay lập tức nó có thể được áp dụng cho vấn đề này. Các hành động được thực hiện khi người dùng thực hiện di chuyển luôn giống nhau và theo cùng một thứ tự, cụ thể là:

  • gửi đá vào lỗ (điều này giống nhau cho tất cả các trò chơi, do đó sẽ được thực hiện trong chính phương thức mẫu)
  • xác định kết quả của việc di chuyển
  • xác định xem trò chơi đã kết thúc vì di chuyển trước đó chưa
  • nếu trò chơi kết thúc, hãy xác định ai đã thắng

Ba bước cuối cùng là tất cả trong mô hình chiến lược của tôi được mô tả ở trên. Tôi đang gặp nhiều rắc rối khi kết hợp cả hai. Một giải pháp khả thi tôi tìm thấy là từ bỏ mô hình chiến lược và thực hiện như sau: nhập mô tả hình ảnh ở đây

Tôi không thực sự thấy sự khác biệt về thiết kế giữa mẫu chiến lược và cái này? Nhưng tôi chắc chắn rằng tôi cần sử dụng một phương thức mẫu (mặc dù tôi chắc chắn về việc phải sử dụng một mẫu chiến lược).

Tôi cũng không thể xác định ai sẽ chịu trách nhiệm tạo TurnTemplateđối tượng, trong khi với mẫu chiến lược tôi cảm thấy tôi có các họ đối tượng (ba quy tắc) mà tôi có thể dễ dàng tạo bằng mô hình nhà máy trừu tượng. Sau đó tôi sẽ có một MancalaRuleFactory, WariRuleFactoryv.v. và họ sẽ tạo ra các thể hiện chính xác của các quy tắc và trao lại cho tôi một RuleSetđối tượng.

Giả sử tôi sử dụng chiến lược + mẫu nhà máy trừu tượng và tôi có một RuleSetđối tượng có thuật toán cho ba quy tắc trong đó. Cách duy nhất tôi cảm thấy tôi vẫn có thể sử dụng mẫu phương thức mẫu với điều này là truyền RuleSetđối tượng này cho tôi TurnTemplate. "Vấn đề" mà sau đó nổi lên là tôi sẽ không bao giờ cần các triển khai cụ thể của mình TurnTemplate, các lớp này sẽ trở nên lỗi thời. Trong các phương thức được bảo vệ của tôi trong TurnTemplatetôi chỉ có thể gọi ruleSet.determineWinner(). Kết quả là, TurnTemplatelớp sẽ không còn trừu tượng mà sẽ phải trở nên cụ thể, liệu nó có còn là một mẫu phương thức mẫu không?

Tóm lại, tôi đang suy nghĩ đúng cách hay tôi đang thiếu một cái gì đó dễ dàng? Nếu tôi đang đi đúng hướng, làm cách nào để kết hợp một mẫu chiến lược và một mẫu phương thức mẫu?


1
Tôi muốn nói rằng suy nghĩ của bạn là khá nhiều điểm. Nếu phản hồi bạn nhận được từ giáo sư của bạn không xác thực điều đó, hãy yêu cầu anh ấy / cô ấy chỉ ra những sai sót, hoặc đưa ra gợi ý về những gì anh ấy sẽ trả lời sau câu trả lời. Ngừng cố gắng đọc tâm trí. Giả sử công cụ về những gì giáo sư của bạn (và sau này là người dùng của bạn) muốn có thể là điều tồi tệ nhất bạn có thể làm.
Marjan Venema

" ... Trong trò chơi của Mancala và Wari, cách người chiến thắng được xác định là hoàn toàn giống nhau và mã sẽ được sao chép. " Tại sao điều đó hàm ý mã được sao chép? Chỉ cần để cả hai lớp gọi cùng một chức năng.
D Drmmr

Câu trả lời:


6

Sau khi nhìn vào thiết kế của bạn, cả hai lần lặp đầu tiên và lần thứ ba của bạn dường như là những thiết kế thanh lịch hơn. Tuy nhiên, bạn đề cập rằng bạn là sinh viên và giáo sư của bạn đã cung cấp cho bạn một số phản hồi. Không biết chính xác bài tập của bạn hoặc mục đích của lớp học là gì hoặc nhiều thông tin hơn về những gì giáo sư của bạn đề xuất, tôi sẽ lấy bất cứ điều gì tôi nói dưới đây với một hạt muối.

Trong thiết kế đầu tiên của bạn, bạn tuyên bố bạn RuleInterfacelà một giao diện xác định cách xử lý lượt của từng người chơi, cách xác định xem trò chơi đã kết thúc chưa và cách xác định người chiến thắng sau khi trò chơi kết thúc. Có vẻ như đó là một giao diện hợp lệ cho một gia đình trò chơi trải nghiệm sự thay đổi. Tuy nhiên, tùy thuộc vào các trò chơi, bạn có thể có mã trùng lặp. Tôi đồng ý rằng sự linh hoạt để thay đổi quy tắc của một trò chơi là một điều tốt, nhưng tôi cũng cho rằng việc sao chép mã là khủng khiếp đối với các khiếm khuyết. Nếu bạn sao chép / dán mã bị lỗi giữa các lần triển khai và một lỗi có trong đó, thì bây giờ bạn có nhiều lỗi cần được sửa ở các vị trí khác nhau. Nếu bạn viết lại các triển khai tại các thời điểm khác nhau, bạn có thể đưa ra các khiếm khuyết ở các vị trí khác nhau. Không ai trong số đó là mong muốn.

Thiết kế thứ hai của bạn có vẻ khá phức tạp, với một cây thừa kế sâu. Ít nhất, nó sâu sắc hơn tôi mong đợi để giải quyết loại vấn đề này. Bạn cũng bắt đầu chia nhỏ chi tiết triển khai thành các lớp khác. Cuối cùng, bạn đang lập mô hình và thực hiện một trò chơi. Đây có thể là một cách tiếp cận thú vị nếu bạn được yêu cầu kết hợp các quy tắc của mình để xác định kết quả của một nước đi, kết thúc trò chơi và một người chiến thắng, dường như không nằm trong các yêu cầu mà bạn đã đề cập . Các trò chơi của bạn là các bộ quy tắc được xác định rõ ràng và tôi sẽ cố gắng gói gọn các trò chơi nhiều nhất có thể vào các thực thể riêng biệt.

Thiết kế thứ ba của bạn là một cái mà tôi thích nhất. Mối quan tâm duy nhất của tôi là nó không ở mức độ trừu tượng. Ngay bây giờ, bạn dường như được mô hình hóa một lượt. Tôi sẽ khuyên bạn nên xem xét thiết kế trò chơi. Hãy xem xét rằng bạn có những người chơi đang di chuyển trên một số loại bảng, sử dụng đá. Trò chơi của bạn yêu cầu những diễn viên này phải có mặt. Từ đó, thuật toán của bạn không phải là doTurn()nhưng playGame(), mà đi từ động thái ban đầu để di chuyển cuối cùng, sau đó nó chấm dứt. Sau mỗi lần di chuyển của người chơi, nó sẽ điều chỉnh trạng thái của trò chơi, xác định xem trò chơi có ở trạng thái cuối không và nếu có, sẽ xác định người chiến thắng.

Tôi sẽ khuyên bạn nên xem xét kỹ hơn các thiết kế đầu tiên và thứ ba của bạn và làm việc với chúng. Nó cũng có thể giúp suy nghĩ về các nguyên mẫu. Các khách hàng sử dụng các giao diện này sẽ trông như thế nào? Liệu một phương pháp thiết kế có ý nghĩa hơn đối với việc triển khai một ứng dụng khách thực sự sẽ khởi tạo một trò chơi và chơi trò chơi? Bạn cần nhận ra những gì nó tương tác. Trong trường hợp cụ thể của bạn, đó là Gamelớp và bất kỳ yếu tố liên quan nào khác - bạn không thể thiết kế tách biệt.


Vì bạn đề cập đến việc bạn là sinh viên, tôi muốn chia sẻ một vài điều từ khi tôi còn là TA cho khóa học thiết kế phần mềm:

  • Các mẫu đơn giản là một cách để nắm bắt những thứ đã hoạt động trong quá khứ, nhưng trừu tượng hóa chúng đến một điểm mà chúng có thể được sử dụng trong các thiết kế khác. Mỗi danh mục các mẫu thiết kế đặt tên cho một mẫu, giải thích ý định của nó và nơi nó có thể được sử dụng, và các tình huống cuối cùng sẽ hạn chế thiết kế của bạn.
  • Thiết kế đi kèm với kinh nghiệm. Cách tốt nhất để có được thiết kế tốt không chỉ đơn giản là tập trung vào các khía cạnh mô hình, mà là nhận ra những gì đi vào việc thực hiện mô hình đó. Thiết kế thanh lịch nhất rất hữu ích nếu không thể thực hiện dễ dàng hoặc không phù hợp với thiết kế lớn hơn của hệ thống hoặc với các hệ thống khác.
  • Rất ít thiết kế là "đúng" hoặc "sai". Miễn là thiết kế đáp ứng các yêu cầu của hệ thống, điều đó không thể sai được. Khi đã có một ánh xạ từ mỗi yêu cầu thành một số đại diện về cách hệ thống sẽ đáp ứng yêu cầu đó, thiết kế không thể sai. Tại thời điểm này, đây chỉ là một định tính về các khái niệm như tính linh hoạt hoặc khả năng sử dụng lại hoặc khả năng kiểm tra hoặc khả năng bảo trì.

Cảm ơn lời khuyên tuyệt vời, đặc biệt là quan điểm của bạn về thực tế rằng nó đã ở mức độ trừu tượng sai. Bây giờ tôi đã thay đổi nó thành một GameTemplatecảm giác tốt hơn rất nhiều. Nó cũng cho phép tôi kết hợp một phương thức xuất xưởng để khởi tạo người chơi, bảng, v.v.
Mekswoll

3

Sự nhầm lẫn của bạn là hợp lý. Có điều là các mẫu không loại trừ lẫn nhau.

Phương thức mẫu là cơ sở cho một loạt các mẫu khác, chẳng hạn như Chiến lược và Nhà nước. Về cơ bản, giao diện Chiến lược chứa một hoặc nhiều phương thức mẫu, mỗi phương thức yêu cầu tất cả các đối tượng thực hiện chiến lược phải có (ít nhất) một cái gì đó giống như phương thức doAction (). Điều này cho phép các chiến lược được thay thế cho nhau.

Trong Java, một giao diện không là gì ngoài một tập hợp các phương thức mẫu. Tương tự như vậy, bất kỳ phương thức trừu tượng nào về cơ bản là một phương thức mẫu. Mô hình này (trong số những người khác) đã được các nhà thiết kế ngôn ngữ biết đến, vì vậy họ đã xây dựng nó.

@ThomasOwens cung cấp lời khuyên tuyệt vời về cách tiếp cận vấn đề cụ thể của bạn.


0

Nếu bạn bị phân tâm bởi các mẫu thiết kế, lời khuyên của tôi dành cho bạn là hãy tạo nguyên mẫu cho trò chơi trước, sau đó các mẫu sẽ nhảy ra khỏi bạn. Tôi không nghĩ rằng thực sự có thể hoặc nên thử thiết kế một hệ thống hoàn hảo trước và sau đó thực hiện nó (theo cách tương tự tôi thấy nó khó hiểu khi mọi người cố gắng viết toàn bộ chương trình trước rồi biên dịch, thay vào đó làm từng chút một .) Vấn đề là không có khả năng bạn sẽ nghĩ đến mọi kịch bản mà logic của bạn sẽ phải xử lý, và trong giai đoạn thực hiện, bạn sẽ mất hết hy vọng hoặc cố gắng bám vào thiết kế thiếu sót ban đầu của mình và thậm chí là hack tệ hơn là không cung cấp gì cả.


2
Mặc dù nói chung tôi đồng ý với bạn , đây thực sự không phải là một câu trả lời giải quyết vấn đề của OP. "Đừng làm vậy" là một câu trả lời, nhưng là một câu trả lời khá kém nếu nó không cung cấp một sự thay thế khả thi.
yannis

@YannisRizos Và mặc dù tôi cũng đồng ý với bạn , tôi vẫn nghĩ anh ấy đã đưa ra lời khuyên hợp lý (hoặc hiểu biết sâu sắc nếu lời khuyên không phải là từ đúng). Vì lý do đó, +1. Mặc dù, vâng, đó không phải là một câu trả lời rất hữu ích.
mua777

-1

Chúng ta hãy xuống đồng thau. Hoàn toàn không cần bất kỳ giao diện Trò chơi nào, không có mẫu thiết kế, không có lớp trừu tượng và không có UML.

Nếu bạn có số lượng lớp hỗ trợ hợp lý, như UI, mô phỏng và bất cứ thứ gì, thì về cơ bản, tất cả các mã không dành riêng cho logic trò chơi của bạn sẽ được sử dụng lại. Hơn nữa, người dùng của bạn không thay đổi trò chơi của mình một cách linh hoạt. Bạn không lật ở tần số 30Hz giữa các trò chơi. Bạn chơi một trò chơi trong khoảng nửa giờ. Vì vậy, đa hình "động" của bạn không thực sự năng động. Nó khá tĩnh.

Vì vậy, cách hợp lý để đi đến đây là sử dụng một sự trừu tượng hóa chức năng chung, như của C # Actionhoặc C ++ std::function, tạo một Mancala, một Wari và một lớp Kalah, và đi từ đó.

std::unordered_map<std::string, std::function<void()>> games = {
    { "Kalah", [] { return Kalah(); } },
    { "Mancala", [] { return Mancala(); } },
    { "Wari", [] { return Wari(); } }
};
void play() {
    std::function<void()> f;
    f = games[GetChoiceFromUI()];
    f();
    if (PlayAgain()) return play();
}
int main() {
    play();
}

Làm xong.

Bạn không gọi Trò chơi. Trò chơi gọi cho bạn.


3
Tôi không thấy làm thế nào điều này là hữu ích cả. Người hỏi câu hỏi này là một sinh viên. Anh ấy hỏi rõ ràng về các nguyên tắc thiết kế và sự tương tác giữa hai mẫu thiết kế. Nói rằng không cần phải có các mẫu thiết kế hoặc UML có thể đúng trong một số trường hợp trong ngành, nhưng suy nghĩ về các mẫu thiết kế, mẫu thiết kế và UML có thể là vấn đề cần được giải quyết.
Thomas Owens

3
Không có gì để nói về họ, bởi vì không có nơi nào họ áp dụng. Không có điểm nào dành thời gian của bạn để suy nghĩ về cách bạn sẽ hoàn toàn nâng cao thiết kế bằng cách sử dụng các mẫu thiết kế, trừ khi bạn dự định đó sẽ là một bài học về cách không sử dụng chúng.
DeadMG

4
Có một xu hướng đáng lo ngại / gây phiền nhiễu trong SoftDev trong đó các mẫu thiết kế được sử dụng được coi là quan trọng hơn là chỉ giải quyết vấn đề. Có một thứ như kỹ thuật quá mức.
James

2
@DeadMG: trong khi cả hai bạn về cơ bản đều đúng, trong trường hợp của OP, vấn đề đang vượt qua bài kiểm tra và giải pháp cho vấn đề đó là sử dụng các mẫu thiết kế và UML. Cho dù chúng tôi có đúng như thế nào, nếu giáo sư của anh ấy không đồng ý với giải pháp của anh ấy, anh ấy sẽ không vượt qua.
Goran Jovic

2
Tôi toàn bộ cuộc đời tôi đã luôn luôn nghĩ rằng nó là "thuế đồng" ... Wow, "đồng thau đinh" làm cho tinh thần cách hơn. lol
mua777
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.