Điều gì tốt hơn IllegalStateException hoặc thực thi phương thức im lặng? [đóng cửa]


16

Giả sử tôi có một lớp MediaPlayer có các phương thức play () và stop (). Chiến lược tốt nhất để sử dụng khi thực hiện phương thức dừng trong trường hợp khi phương thức chơi chưa được gọi trước đó. Tôi thấy hai tùy chọn: đưa ra một ngoại lệ vì người chơi không ở trạng thái thích hợp hoặc âm thầm bỏ qua các cuộc gọi đến phương thức dừng.

Điều gì sẽ là quy tắc chung khi một phương thức không được gọi là trong một số trường hợp, nhưng việc thực thi nó không gây hại cho chương trình nói chung?


21
Đừng sử dụng ngoại lệ để mô hình hóa hành vi không đặc biệt.
Alexander - Phục hồi Monica

1
Chào! Tôi không nghĩ đó là một bản sao. Câu hỏi của tôi là nhiều hơn về IllegalStateException và câu hỏi trên là về việc sử dụng các ngoại lệ nói chung.
x2bool

1
Thay vì JUST âm thầm thất bại, tại sao CSONG không ghi lại sự bất thường như một lời cảnh báo? Chắc chắn Java bạn đang sử dụng hỗ trợ các mức nhật ký khác nhau (ERROR, WARN, INFO, DEBUG).
Eric Seastrand

3
Lưu ý rằng Set.add không ném ngoại lệ nếu mục đã có trong tập hợp. Mục đích của nó là "đảm bảo phần tử nằm trong tập hợp", thay vì "thêm mục vào tập hợp", vì vậy nó đạt được mục đích của nó bằng cách không làm gì nếu phần tử đã có trong tập hợp.
dùng253751

2
Lời của ngày: idempotence
Jules

Câu trả lời:


37

Không có quy tắc. Điều đó hoàn toàn phụ thuộc vào cách bạn muốn làm cho API của mình "cảm thấy".

Cá nhân, trong một máy nghe nhạc, tôi nghĩ rằng một sự chuyển tiếp từ nhà nước Stoppedđến Stoppedbằng phương tiện của phương pháp này Stop()là một chuyển trạng thái hoàn toàn hợp lệ. Nó không có ý nghĩa lắm, nhưng nó hợp lệ. Với suy nghĩ này, việc ném một ngoại lệ có vẻ mang tính mô phạm và không công bằng. Nó sẽ làm cho API cảm thấy giống như xã hội khi nói chuyện với đứa trẻ phiền phức trên xe buýt của trường. Bạn đang bị mắc kẹt với tình huống gây phiền nhiễu, nhưng bạn có thể giải quyết nó.

Một cách tiếp cận "hòa đồng" hơn là thừa nhận rằng quá trình chuyển đổi là vô hại nhất và hãy tử tế với các nhà phát triển tiêu dùng của bạn bằng cách cho phép nó.

Vì vậy, nếu nó tùy thuộc vào tôi, tôi sẽ bỏ qua ngoại lệ.


15
Câu trả lời này nhắc nhở chúng ta rằng đôi khi đó là một ý tưởng tốt để vạch ra các hiệu ứng chuyển tiếp trạng thái cho thậm chí tương tác đơn giản.

6
Với suy nghĩ này, việc ném một ngoại lệ có vẻ mang tính mô phạm và không công bằng. Nó sẽ làm cho API cảm thấy giống như xã hội khi nói chuyện với đứa trẻ phiền phức trên xe buýt của trường. > Ngoại lệ không được thiết kế để trừng phạt bạn: Chúng được thiết kế để cho bạn biết điều gì đó bất ngờ đã xảy ra. Cá nhân tôi sẽ rất biết ơn về một MediaPlayer.stop()phương pháp đã tạo ra IllegalStateExceptionthay vì mất hàng giờ để gỡ lỗi mã và tự hỏi tại sao Địa ngục "không có gì xảy ra" (tức là "nó không hoạt động").
errantlinguist

3
Tất nhiên, nếu thiết kế của bạn cho biết quá trình chuyển đổi loopback không hợp lệ thì CÓ, bạn nên ném ngoại lệ. Tuy nhiên, câu trả lời của tôi là về một thiết kế trong đó quá trình chuyển đổi đó hoàn toàn ổn.
MetaFight

1
StopOrThrow()Nghe thật kinh khủng. Nếu bạn đang đi xuống con hẻm đó tại sao không sử dụng mô hình chuẩn TryStop()? Ngoài ra, nói chung, khi hành vi của API không rõ ràng (vì hầu hết trong số họ là), các nhà phát triển không mong đợi chỉ đơn giản là đoán hoặc thử nghiệm, họ sẽ xem xét tài liệu. Đó là lý do tại sao tôi thích MSDN rất nhiều.
MetaFight

1
Cá nhân tôi thích tùy chọn không nhanh, vì vậy tôi sẽ tìm đến IllegalStateException để cho người dùng API biết rằng có gì đó không đúng trong logic của anh ta, ngay cả khi nó vô hại. Tôi thường tự nhận những ngoại lệ đó từ mã của riêng mình, thực sự hữu ích khi phát hiện ra rằng công việc không được phép của tôi đã sai
Walfrat

17

Có hai loại hành động riêng biệt mà người ta có thể muốn thực hiện:

  1. Đồng thời kiểm tra xem một cái gì đó ở trạng thái này, và thay đổi nó sang trạng thái khác.

  2. Đặt một cái gì đó đến một trạng thái cụ thể, mà không quan tâm đến trạng thái trước đó.

Một số bối cảnh yêu cầu một hành động, và một số yêu cầu hành động khác. Nếu trình phát đa phương tiện đến cuối nội dung sẽ vẫn ở trạng thái "phát lại", nhưng với vị trí bị đóng băng ở cuối, thì phương thức đồng thời xác nhận rằng trình phát ở trạng thái phát lại trong khi đặt thành "dừng" trạng thái có thể hữu ích nếu mã muốn đảm bảo rằng không có gì khiến phát lại bị lỗi trước yêu cầu dừng (điều này có thể quan trọng nếu ví dụ: một cái gì đó đang ghi lại nội dung được phát lại như một phương tiện chuyển đổi phương tiện từ định dạng này sang định dạng khác) . Tuy nhiên, trong hầu hết các trường hợp, điều quan trọng là sau khi hoạt động, trình phát phương tiện ở trạng thái mong đợi (tức là đã dừng).

Nếu một trình phát đa phương tiện tự động dừng khi đến cuối phương tiện, một chức năng khẳng định rằng trình phát đang chạy có thể sẽ gây khó chịu hơn là hữu ích, nhưng trong một số trường hợp, liệu trình phát đó có chạy hay không khi dừng. có ích Có lẽ cách tiếp cận tốt nhất để phục vụ cho cả hai nhu cầu là có chức năng trả về giá trị cho biết trạng thái trước đó của người chơi. Mã quan tâm đến trạng thái đó có thể kiểm tra giá trị trả về; mã mà không quan tâm đơn giản có thể bỏ qua nó.


2
+1 cho lưu ý về việc trả lại trạng thái cũ: Điều đó cho phép thực hiện nó theo cách làm cho toàn bộ hoạt động (truy vấn trạng thái và chuyển sang trạng thái xác định) nguyên tử, ít nhất là một tính năng hay. Nó sẽ giúp dễ dàng hơn để viết mã người dùng mạnh mẽ mà không thất bại do một số điều kiện chủng tộc kỳ lạ.
cmaster - phục hồi monica

Một bool TryStop()và một void Stop()ví dụ mã sẽ làm cho điều này một câu trả lời thực sự xuất sắc.
RubberDuck

2
@RubberDuck: Đó sẽ không phải là một mô hình tốt. Tên TryStopnày có nghĩa là không nên ném ngoại lệ nếu người chơi không thể bị buộc phải ở trạng thái dừng. Cố gắng dừng người chơi khi nó đã dừng không phải là một điều kiện ngoại lệ, nhưng đó là điều kiện mà người gọi có thể quan tâm.
supercat

1
Sau đó, tôi đã hiểu nhầm câu trả lời của bạn @supercat
RubberDuck

2
Tôi muốn chỉ ra rằng thử nghiệm và thiết lập theo cách này KHÔNG phải là vi phạm luật pháp của người cung cấp, API cũng cung cấp một cách để kiểm tra trạng thái phát lại mà không thay đổi nó. Đây có thể là một phương pháp hoàn toàn khác, nói isPlaying().
candied_orange

11

Không có quy tắc chung. Trong trường hợp cụ thể này, ý định của người dùng API của bạn là ngăn người chơi phát phương tiện. Nếu người chơi không chơi phương tiện, MediaPlayer.stop()có thể không làm gì cả và mục tiêu của người gọi phương thức vẫn sẽ đạt được - phương tiện không phát.

Việc ném một ngoại lệ sẽ yêu cầu người dùng API kiểm tra xem người chơi hiện đang chơi hay bắt và xử lý ngoại lệ đó. Điều này sẽ làm cho API trở nên dễ sử dụng hơn.


11

Mục đích của các trường hợp ngoại lệ không phải là để báo hiệu rằng một cái gì đó xấu đã xảy ra; đó là để báo hiệu rằng

  1. Một cái gì đó xấu đã xảy ra
  2. mà tôi không biết làm thế nào để sửa chữa ở đây
  3. rằng người gọi, hoặc một cái gì đó trong cuộc gọi từ nó nên biết cách đối phó
  4. vì vậy tôi nhanh chóng giải cứu, tạm dừng việc thực thi đường dẫn mã hiện tại để ngăn ngừa thiệt hại hoặc hỏng dữ liệu và để lại cho người gọi để dọn dẹp

Nếu cố gắng gọi đến Stopmột MediaPlayerđó là đã ở trong tình trạng dừng lại, đây không phải là một vấn đề mà các MediaPlayercó thể không quyết tâm (nó chỉ đơn giản là không thể làm gì.) Nó không phải là một vấn đề rằng, nếu tiếp tục, sẽ dẫn đến làm hỏng hoặc dữ liệu tham nhũng, vì nó có thể thành công chỉ đơn giản bằng cách không làm gì. Và nó không thực sự là một vấn đề mà nó hợp lý hơn để mong đợi người gọi có thể giải quyết hơn MediaPlayer.

Do đó, bạn không nên ném ngoại lệ trong tình huống này.


+1. Đây là câu trả lời đầu tiên cho thấy tại sao một ngoại lệ không phù hợp ở đây. Trường hợp ngoại lệ chỉ ra rằng người gọi có thể cần phải biết về trường hợp đặc biệt. Trong trường hợp này, gần như chắc chắn khách hàng của lớp đang nghi vấn sẽ không quan tâm liệu việc gọi 'stop ()' có thực sự gây ra sự chuyển đổi trạng thái hay không, vì vậy có thể sẽ không muốn biết về một ngoại lệ.
Jules

5

Nhìn nó theo cách này:

Nếu máy khách gọi Stop () khi người chơi không chơi, thì Stop () sẽ tự động thành công vì trình phát hiện đang ở trạng thái dừng.


3

Quy tắc là bạn làm những gì hợp đồng của phương pháp của bạn yêu cầu.

Tôi có thể thấy nhiều cách để xác định các hợp đồng có ý nghĩa cho một stopphương pháp như vậy . Nó có thể là hoàn toàn hợp lệ cho stopphương pháp để làm hoàn toàn không có gì nếu người chơi không chơi. Trong trường hợp đó, bạn xác định API của mình theo mục tiêu của nó. Bạn muốn chuyển sang stoppedtrạng thái và stopphương thức thực hiện điều đó - chỉ bằng cách chuyển từ stoppedtrạng thái sang chính nó mà không gặp lỗi.

Có bất kỳ lý do tại sao bạn muốn ném Ngoại lệ? Nếu mã người dùng cuối cùng sẽ trông như thế này:

try {
    player.stop();
} catch(IllegalStateException e) {
    // do nothing, player was already stopped
}

sau đó không có lợi ích gì khi có ngoại lệ đó. Vì vậy, câu hỏi là, người dùng sẽ quan tâm đến thực tế là người chơi đã dừng lại? Liệu anh ta có một wa khác để truy vấn nó?

Người chơi có thể quan sát được, và đã có thể thông báo cho các quan sát viên về những điều nhất định - ví dụ như thông báo các nhà quan sát khi nó transitons từ playingđể stoppingđến stopped. Trong trường hợp này, có phương pháp ném ngoại lệ là không cần thiết. Gọi stopsẽ không làm gì nếu người chơi đã dừng và gọi nó khi không dừng sẽ thông báo cho người quan sát về quá trình chuyển đổi.

tất cả trong tất cả, nó phụ thuộc vào nơi logic của bạn sẽ kết thúc. Nhưng tôi nghĩ có những lựa chọn thiết kế tốt hơn sau đó ném một ngoại lệ.

Bạn nên ném một ngoại lệ nếu người gọi phải can thiệp. Trong trường hợp này anh ta không phải làm thế, bạn chỉ cần để người chơi như vậy và nó vẫn tiếp tục hoạt động.


3

Có một chiến lược chung đơn giản giúp bạn đưa ra quyết định này.

Xem xét làm thế nào ngoại lệ sẽ được xử lý nếu nó được ném.

Vì vậy, hãy tưởng tượng trình phát nhạc của bạn, người dùng nhấp vào dừng và sau đó dừng lại. Bạn có muốn hiển thị một thông báo lỗi trong kịch bản đó? Tôi chưa thấy một người chơi nào. Bạn có muốn hành vi ứng dụng khác đi không chỉ nhấp vào dừng một lần (như đăng nhập sự kiện hoặc gửi báo cáo lỗi trong nền)? Chắc là không.

Điều đó có nghĩa là ngoại lệ sẽ cần phải bị bắt và nuốt ở đâu đó. Và điều đó có nghĩa là bạn tốt hơn hết là đừng ném ngoại lệ ngay từ đầu vì bạn không muốn thực hiện một hành động khác .

Điều này không chỉ áp dụng cho các trường hợp ngoại lệ mà là bất kỳ loại phân nhánh nào: về cơ bản nếu không cần có sự khác biệt có thể quan sát được trong hành vi, thì không cần phải phân nhánh.

Điều đó nói rằng, không có nhiều tác hại trong việc xác định stop()phương thức của bạn để trả về một booleangiá trị enum cho biết việc dừng là "thành công". Bạn có thể sẽ không bao giờ sử dụng nó, nhưng giá trị trả về có thể dễ dàng bị bỏ qua và tự nhiên hơn là một ngoại lệ.


2

Đây là cách Android thực hiện: MediaPlayer

Tóm lại, stopkhi startchưa được gọi không phải là vấn đề, hệ thống sẽ ở trạng thái dừng, nhưng nếu được gọi cho một người chơi thậm chí không biết nó đang chơi gì, một ngoại lệ sẽ bị ném, vì không có lý do chính đáng để gọi Dừng tại đó.


1

Điều gì sẽ là quy tắc chung khi một phương thức không được gọi là trong một số trường hợp, nhưng việc thực thi nó không gây hại cho chương trình nói chung?

Tôi thấy những gì có thể là một mâu thuẫn nhỏ trong tuyên bố của bạn có thể làm cho câu trả lời rõ ràng cho bạn. Tại sao phương thức này không được gọiphương thức thực thi không gây hại ?

Tại sao phương thức "không được gọi là"? Đó dường như là một hạn chế tự áp đặt. Nếu không có "tác hại" hoặc tác động đến API của bạn, thì đó không phải là ngoại lệ. Nếu phương thức thực sự không nên được gọi bởi vì nó có thể tạo ra các trạng thái không hợp lệ hoặc không thể đoán trước, thì nên ném một ngoại lệ.

Ví dụ: nếu tôi đi đến một đầu DVD và nhấn "dừng" trước khi nhấn "bắt đầu" và nó bị hỏng, điều đó sẽ không có ý nghĩa với tôi. Nó chỉ nên ngồi ở đó hoặc, trường hợp xấu hơn, thừa nhận "dừng" trên màn hình. Một lỗi sẽ gây phiền nhiễu và không hữu ích trong bất kỳ cách nào.

Tuy nhiên, tôi có thể đặt mã báo động để tắt "khi nó tắt (gọi phương thức) không, điều đó có thể khiến nó đi vào trạng thái ngăn không cho nó kích hoạt đúng cách sau này không? Nếu vậy, sau đó ném một lỗi mặc dù, về mặt kỹ thuật, "không có hại gì" vì có thể có vấn đề sau này. Tôi muốn biết về điều này ngay cả khi nó không thực sự đi vào trạng thái đó. Chỉ cần khả năng là đủ. Đây sẽ là một IllegalStateException.

Trong trường hợp của bạn, nếu máy trạng thái của bạn có thể xử lý cuộc gọi không hợp lệ / không cần thiết thì hãy bỏ qua nó, nếu không sẽ gây ra lỗi.

BIÊN TẬP:

Lưu ý rằng trình biên dịch không gọi lỗi nếu bạn đặt biến hai lần mà không kiểm tra giá trị. Nó cũng không ngăn bạn khởi tạo lại một biến. Có nhiều hành động có thể được coi là "lỗi" từ một khía cạnh, nhưng chỉ là "không hiệu quả", "không cần thiết", "vô nghĩa", v.v. Tôi đã cố gắng đưa ra quan điểm đó trong câu trả lời của mình - nói chung những điều này không được xem xét một "lỗi" bởi vì nó không dẫn đến bất cứ điều gì bất ngờ. Bạn có lẽ nên tiếp cận vấn đề của bạn tương tự.


Nó không được gọi vì gọi nó chỉ ra lỗi trong người gọi.
dùng253751

@immibis: Không nhất thiết. Chẳng hạn, người gọi đó có thể là người nghe khi nhấp vào một số nút UI. (Là người dùng, có thể bạn sẽ không thích thông báo lỗi nếu bạn vô tình nhấp vào nút dừng nếu phương tiện đã dừng.)
meriton - đình công vào

@meriton Nếu đó là trình nghe nhấp chuột của nút UI thì câu trả lời sẽ rất rõ ràng - "làm bất cứ điều gì bạn muốn xảy ra nếu nhấn nút này". Rõ ràng là không, đó là một cái gì đó bên trong ứng dụng.
dùng253751

@immibis - Tôi đã chỉnh sửa phản hồi của mình. Tôi hy vọng nó sẽ giúp.
Jim

1

Chính xác thì làm gì MediaPlayer.play()MediaPlayer.stop()làm gì? - chúng có phải là trình lắng nghe sự kiện cho đầu vào của người dùng hay chúng thực sự là các phương thức bắt đầu một số luồng phương tiện trên hệ thống? Nếu tất cả họ là người nghe cho đầu vào của người dùng, thì họ hoàn toàn không làm gì cả (mặc dù đó ít nhất là một ý tưởng tốt để đăng nhập chúng ở đâu đó). Tuy nhiên, nếu chúng ảnh hưởng đến mô hình mà UI của bạn đang điều khiển, thì họ có thể ném IllegalStateExceptionvì người chơi nên có một số loại isPlaying=truehoặc isPlaying=falsetrạng thái (nó không cần phải là cờ Boolean thực sự như được viết ở đây), và vì vậy khi bạn gọi MediaPlayer.stop()khi nào isPlaying=false, phương thức thực sự không thể "dừng" MediaPlayervì đối tượng không ở trạng thái thích hợp bị dừng - xem mô tả vềjava.lang.IllegalStateException lớp học:

Tín hiệu cho thấy một phương thức đã được gọi vào thời điểm bất hợp pháp hoặc không phù hợp. Nói cách khác, môi trường Java hoặc ứng dụng Java không ở trạng thái thích hợp cho hoạt động được yêu cầu.

Tại sao ném ngoại lệ có thể là tốt

Rất nhiều người dường như nghĩ rằng các ngoại lệ nói chung là xấu, vì trong đó họ không bao giờ nên bị ném (xem Joel trên Phần mềm ). Tuy nhiên, giả sử bạn có một MediaPlayerGUI.notifyPlayButton()cuộc gọi MediaPlayer.play()MediaPlayer.play()gọi một loạt các mã khác và ở đâu đó trong dòng giao diện với nó, ví dụ PulseAudio , nhưng tôi (nhà phát triển) không biết nơi nào vì tôi không viết tất cả mã đó.

Sau đó, một ngày trong khi làm việc với mã, tôi bấm "phát" và không có gì xảy ra. Nếu MediaPlayerGUIController.notifyPlayButton()ghi nhật ký một cái gì đó, ít nhất tôi có thể nhìn vào nhật ký và kiểm tra xem nút bấm trên thực tế đã được đăng ký chưa ... nhưng tại sao nó không phát? Chà, thực tế là có gì đó không ổn với trình bao bọc PulseAudio MediaPlayer.play()gọi. Tôi nhấp vào nút "phát" lần nữa và lần này tôi nhận được IllegalStateException:

 Exception in thread "main" java.lang.IllegalStateException: MediaPlayer already in play state.

     at org.superdupermediaplayer.MediaPlayer.play(MediaPlayer.java:16)
     at org.superdupermediaplayer.gui.MediaPlayerGUIController.notifyPlayButton(MediaPlayerGUIController.java:25)
     at org.superdupermediaplayer.gui.MediaPlayerGUI.main(MediaPlayerGUI.java:14)

Bằng cách nhìn vào dấu vết ngăn xếp đó, tôi có thể bỏ qua mọi thứ trước MediaPlayer.play()khi gỡ lỗi và dành thời gian để tìm hiểu lý do tại sao ví dụ như không có tin nhắn nào được chuyển đến PulseAudio để bắt đầu một luồng âm thanh.

Mặt khác, nếu bạn không đưa ra một ngoại lệ, tôi sẽ không có gì để bắt đầu làm việc ngoài việc: "Chương trình ngu ngốc không phát bất kỳ bản nhạc nào"; Mặc dù không phải là xấu như rõ ràng ẩn lỗi như thực sự nuốt một ngoại lệ mà đã được trên thực tế ném , bạn vẫn có khả năng lãng phí thời gian của người khác khi có điều gì làm sai đi ... vì vậy hãy thoải mái và ném một ngoại lệ vào họ.


0

Tôi thích thiết kế API theo cách khiến người tiêu dùng khó mắc hoặc không thể mắc lỗi. Ví dụ, thay vì có MediaPlayer.play()MediaPlayer.stop(), bạn có thể cung cấp các MediaPlayer.playToggle()nút chuyển đổi giữa "dừng" và "chơi". Theo cách này, phương thức này luôn an toàn để gọi - không có nguy cơ rơi vào trạng thái bất hợp pháp.

Tất nhiên, điều này không phải lúc nào cũng có thể hoặc dễ làm. Ví dụ bạn đưa ra có thể so sánh với việc thử xóa một phần tử đã bị xóa khỏi danh sách. Bạn có thể

  • thực dụng về nó và không ném bất kỳ lỗi nào. Điều này chắc chắn đơn giản hóa rất nhiều mã, ví dụ, thay vì phải viết if (list.contains(x)) { list.remove(x) }bạn chỉ cần list.remove(x)). Nhưng, nó cũng có thể che giấu lỗi.
  • hoặc bạn có thể là người phạm tội và báo hiệu lỗi rằng danh sách không chứa phần tử đó. Đôi khi mã có thể trở nên phức tạp hơn, vì bạn liên tục phải xác minh xem các điều kiện trước có được thỏa mãn hay không trước khi gọi phương thức, nhưng nhược điểm là các lỗi cuối cùng dễ theo dõi hơn.

Nếu việc gọi MediaPlayer.stop()khi nó đã dừng không có hại trong ứng dụng của bạn, thì tôi sẽ để nó chạy một cách im lặng vì nó đơn giản hóa mã và tôi có một điều cho các phương thức tạm thời. Nhưng nếu bạn hoàn toàn chắc chắn MediaPlayer.stop()sẽ không bao giờ được gọi trong các điều kiện đó, thì tôi sẽ gặp lỗi vì có thể có lỗi ở đâu đó trong mã và ngoại lệ sẽ giúp theo dõi nó.


3
Tôi không đồng ý về playToggle()việc dễ sử dụng hơn: Để đạt được hiệu quả mong muốn (người chơi chơi hay không chơi), bạn sẽ được yêu cầu phải biết trạng thái hiện tại của nó. Vì vậy, nếu bạn nhận được đầu vào của người dùng yêu cầu bạn dừng trình phát, trước tiên bạn cần hỏi xem người chơi có đang chơi hay không, sau đó chuyển trạng thái của nó hay không tùy thuộc vào câu trả lời. Điều đó cồng kềnh hơn nhiều so với việc chỉ gọi một stop()phương thức và được thực hiện với nó.
cmaster - phục hồi monica

Chà, tôi chưa bao giờ nói nó dễ sử dụng hơn - tôi khẳng định rằng nó an toàn hơn. Thêm vào đó, ví dụ của bạn giả định rằng người dùng sẽ được cung cấp các nút dừng và phát riêng biệt. Nếu đó thực sự là trường hợp thì có, a playTogglesẽ rất cồng kềnh khi sử dụng. Nhưng nếu người dùng cũng được cung cấp một nút chuyển đổi, thì playTogglenó sẽ dễ sử dụng hơn là phát / dừng.
Pedro Coleues
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.