คำถามติดแท็ก design

คำถามเกี่ยวกับการแก้ปัญหาและการวางแผนแก้ปัญหาผ่านการออกแบบซอฟต์แวร์

7
การออกแบบ REST api โดย URI เทียบกับสตริงแบบสอบถาม
สมมติว่าฉันมีสามทรัพยากรที่เกี่ยวข้องดังนี้: Grandparent (collection) -> Parent (collection) -> and Child (collection) ด้านบนแสดงให้เห็นถึงความสัมพันธ์ระหว่างทรัพยากรเหล่านี้เช่น: ปู่ย่าตายายแต่ละคนสามารถแมปกับผู้ปกครองหนึ่งหรือหลายคน ผู้ปกครองแต่ละคนสามารถแมปกับเด็กคนหนึ่งหรือหลายคน ฉันต้องการความสามารถในการสนับสนุนการค้นหากับทรัพยากรลูก แต่ด้วยเกณฑ์ตัวกรอง: หากลูกค้าของฉันส่งรหัสอ้างอิงถึงปู่ย่าตายายให้ฉันฉันต้องการค้นหาเฉพาะเด็กที่เป็นทายาทสายตรงของปู่ย่าตายายนั้นเท่านั้น หากลูกค้าของฉันส่งรหัสอ้างอิงไปยังผู้ปกครองฉันต้องการค้นหาเฉพาะเด็กที่เป็นผู้สืบทอดโดยตรงจากผู้ปกครองของฉัน ฉันคิดถึงบางสิ่งเช่นนั้น: GET /myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text} และ GET /myservice/api/v1/parents/{parentID}/children?search={text} สำหรับข้อกำหนดข้างต้นตามลำดับ แต่ฉันสามารถทำอะไรเช่นนี้: GET /myservice/api/v1/children?search={text}&grandparentID={id}&parentID=${id} ในการออกแบบนี้ฉันสามารถอนุญาตให้ลูกค้าของฉันส่งต่อฉันอย่างใดอย่างหนึ่งในสตริงการสืบค้น: grandparentID หรือ parentID แต่ไม่ใช่ทั้งสองอย่าง คำถามของฉันคือ: 1) การออกแบบ API ใดที่สงบมากขึ้นและทำไม ความหมายพวกมันหมายถึงและประพฤติตนในลักษณะเดียวกัน ทรัพยากรสุดท้ายใน URI คือ "children" หมายความว่าไคลเอ็นต์กำลังทำงานบนทรัพยากรชายด์อย่างมีประสิทธิภาพ 2) อะไรคือข้อดีข้อเสียของแต่ละคนในแง่ของความเข้าใจในมุมมองของลูกค้าและการบำรุงรักษาจากมุมมองของนักออกแบบ 3) สตริงการสืบค้นที่ใช้จริงๆนอกเหนือจาก "การกรอง" ในทรัพยากรของคุณคืออะไร หากคุณใช้วิธีแรกพารามิเตอร์ตัวกรองจะถูกฝังใน …
73 design  rest  api 

7
ฉันควรทำตามเส้นทางปกติหรือล้มเหลว แต่เนิ่นๆ
จากหนังสือCode Completeมาพร้อมคำพูดต่อไปนี้: "ใส่เคสปกติหลังจากifดีกว่าelse" ซึ่งหมายความว่าควรมีข้อยกเว้น / การเบี่ยงเบนจากเส้นทางมาตรฐานในelseกรณี แต่โปรแกรมเมอร์ในทางปฏิบัติสอนให้เรา "ผิดพลาดเร็ว" (หน้า 120) ฉันควรทำตามกฎใด
73 design 

11
คำแนะนำในการออกแบบเว็บแอปพลิเคชันด้วยอายุการใช้งานมากกว่า 40 ปี
สถานการณ์ ขณะนี้ฉันอยู่นอกเหนือโครงการดูแลสุขภาพที่มีความต้องการหลักคือการเก็บข้อมูลที่มีคุณลักษณะที่ไม่รู้จักโดยใช้แบบฟอร์มที่ผู้ใช้สร้างขึ้นโดยผู้ให้บริการด้านสุขภาพ ข้อกำหนดที่สองคือความสมบูรณ์ของข้อมูลเป็นกุญแจสำคัญและแอปพลิเคชันจะใช้งานมากกว่า 40 ปี ขณะนี้เรากำลังย้ายข้อมูลลูกค้าจาก 40 ปีที่ผ่านมาจากแหล่งข้อมูลต่างๆ (กระดาษ, Excel, Access, ฯลฯ ... ) ไปยังฐานข้อมูล ข้อกำหนดในอนาคตคือ: การจัดการเวิร์กโฟลว์ของแบบฟอร์ม การจัดการตารางเวลาของแบบฟอร์ม ความปลอดภัย / การจัดการตามบทบาท เครื่องมือสร้างรายงาน รองรับมือถือ / แท็บเล็ต สถานการณ์ เพียง 6 เดือนเท่านั้นสถาปนิก / โปรแกรมเมอร์อาวุโส (ที่เซ็นสัญญา) คนปัจจุบันใช้แนวทาง "เร็ว" และได้ออกแบบระบบที่ไม่ดี ฐานข้อมูลไม่ได้รับการปรับให้เป็นมาตรฐาน, โค้ดนั้นเป็นแบบคู่, เทียร์ไม่มีวัตถุประสงค์เฉพาะและข้อมูลเริ่มหายไปเนื่องจากเขาได้ออกแบบถั่วบางตัวเพื่อทำการ "ลบ" บนฐานข้อมูล รหัสฐานนั้นเต็มไปด้วยฟองเลือดมากและมีงานที่ต้องทำการซิงโครไนซ์ข้อมูลเนื่องจากฐานข้อมูลไม่ได้ถูกทำให้เป็นมาตรฐาน วิธีการของเขาคือการพึ่งพางานสำรองเพื่อกู้คืนข้อมูลที่หายไปและดูเหมือนจะไม่เชื่อในการกู้คืนข้อมูล หลังจากนำเสนอสิ่งที่ฉันพบต่อ PM สถาปนิกจะถูกลบออกเมื่อสัญญาของเขาสิ้นสุดลง ฉันได้รับมอบหมายให้สร้างแอปพลิเคชันนี้อีกครั้ง ทีมของฉันประกอบด้วยฉันและโปรแกรมเมอร์ระดับต้นหนึ่งคน เราไม่มีทรัพยากรอื่น ๆ เราได้รับสิทธิ์การแช่แข็ง …

9
เหตุใดจึงใช้คลาสบางส่วน
ในความเข้าใจของฉันpartialคำหลักไม่ทำอะไรเลยนอกจากอนุญาตให้แบ่งคลาสระหว่างไฟล์ต้นฉบับหลาย ๆ ไฟล์ มีเหตุผลใดที่จะทำสิ่งนี้นอกเหนือจากการจัดระเบียบรหัสหรือไม่ ฉันเคยเห็นมันใช้สำหรับสิ่งนั้นในคลาส UI ที่สร้างขึ้น ดูเหมือนว่าเหตุผลที่ไม่ดีในการสร้างคำหลักทั้งหมด ถ้าคลาสมีขนาดใหญ่พอที่จะต้องใช้หลายไฟล์มันอาจจะทำมากเกินไป ฉันคิดว่าบางทีคุณสามารถใช้มันเพื่อกำหนดคลาสสำหรับโปรแกรมเมอร์อื่นบางส่วนเพื่อให้สมบูรณ์ แต่มันจะดีกว่าถ้าสร้างคลาสที่เป็นนามธรรม

12
SQL: สตริงว่างกับค่า NULL
ฉันรู้ว่าหัวข้อนี้ขัดแย้งกันเล็กน้อยและมีบทความ / ความคิดเห็นมากมายลอยอยู่ในอินเทอร์เน็ต โชคไม่ดีที่พวกเขาส่วนใหญ่คิดว่าบุคคลนั้นไม่รู้ว่าความแตกต่างระหว่าง NULL และสตริงว่างคืออะไร ดังนั้นพวกเขาจึงบอกเล่าเรื่องราวเกี่ยวกับผลลัพธ์ที่น่าประหลาดใจด้วยการรวม / สรุปรวมและโดยทั่วไปจะทำบทเรียน SQL ขั้นสูงเพิ่มเติม โดยการทำเช่นนี้พวกเขาพลาดจุดทั้งหมดและไม่มีประโยชน์สำหรับฉัน ดังนั้นหวังว่าคำถามนี้และคำตอบทั้งหมดจะย้ายไปข้างหน้าเล็กน้อย สมมติว่าฉันมีตารางที่มีข้อมูลส่วนบุคคล (ชื่อ, วันเกิด, ฯลฯ ) โดยที่หนึ่งในคอลัมน์คือที่อยู่อีเมลที่มีประเภท varchar เราคิดว่าด้วยเหตุผลบางคนบางคนอาจไม่ต้องการให้ที่อยู่อีเมล เมื่อแทรกข้อมูลดังกล่าว (ไม่มีอีเมล) ลงในตารางมีสองตัวเลือกที่ใช้ได้: ตั้งค่าเซลล์เป็น NULL หรือตั้งค่าเป็นสตริงว่าง ('') สมมติว่าฉันทราบถึงผลกระทบทางเทคนิคทั้งหมดของการเลือกโซลูชันหนึ่งมากกว่าโซลูชันอื่นและฉันสามารถสร้างแบบสอบถาม SQL ที่ถูกต้องสำหรับสถานการณ์ใดสถานการณ์หนึ่ง ปัญหาคือแม้เมื่อค่าทั้งสองแตกต่างกันในระดับเทคนิคพวกเขาจะเหมือนกันในระดับตรรกะ หลังจากดู NULL และ '' ฉันได้ข้อสรุปเดียว: ฉันไม่รู้ที่อยู่อีเมลของผู้ชายคนนั้น ไม่ว่าฉันจะพยายามมากแค่ไหน ฉันไม่สามารถส่งอีเมลโดยใช้ NULL หรือสตริงว่างเปล่าได้ดังนั้นเซิร์ฟเวอร์ SMTP ส่วนใหญ่ก็เห็นด้วยกับเหตุผลของฉัน ดังนั้นฉันมักจะใช้ค่า NULL ที่ฉันไม่ทราบค่าและพิจารณาสตริงว่างเปล่าเป็นสิ่งที่ไม่ดี หลังจากการพูดคุยอย่างเข้มข้นกับเพื่อนร่วมงานฉันมาด้วยคำถามสองข้อ: ฉันถูกสมมติว่าการใช้สตริงว่างเปล่าสำหรับค่าที่ไม่รู้จักทำให้ฐานข้อมูล "โกหก" …
72 design  database  sql  strings  null 

7
เมื่อใดจึงควรใช้คลาสนามธรรมแทนอินเทอร์เฟซที่มีวิธีการขยายใน C #
"คลาสนามธรรม" และ "อินเทอร์เฟซ" เป็นแนวคิดที่คล้ายกันโดยอินเทอร์เฟซเป็นนามธรรมของทั้งสอง ปัจจัยที่แตกต่างอย่างหนึ่งคือคลาสนามธรรมจะจัดเตรียมวิธีการใช้งานสำหรับคลาสที่ได้รับเมื่อต้องการ อย่างไรก็ตามใน C # ปัจจัยที่มีความแตกต่างนี้ได้รับการลดลงโดยการแนะนำวิธีการขยายล่าสุดซึ่งช่วยให้การใช้งานมีไว้สำหรับวิธีการอินเทอร์เฟซ ปัจจัยที่มีความแตกต่างอีกอย่างหนึ่งคือคลาสสามารถสืบทอดคลาสนามธรรมเพียงคลาสเดียวเท่านั้น (กล่าวคือไม่มีการสืบทอดหลายคลาส) แต่สามารถใช้หลายอินเตอร์เฟสได้ ทำให้ส่วนต่อประสานที่ จำกัด น้อยลงและมีความยืดหยุ่นมากขึ้น ดังนั้นใน C # เราควรใช้คลาสนามธรรมแทนอินเทอร์เฟซกับวิธีการส่วนขยายหรือไม่ ตัวอย่างที่น่าสังเกตของโมเดลวิธีส่วนต่อประสาน + ส่วนต่อขยายคือ LINQ โดยที่ฟังก์ชันการสืบค้นมีให้สำหรับประเภทใดก็ตามที่ใช้IEnumerableวิธีการขยายจำนวนมาก

12
“ ทุกอย่างคือแผนที่” ฉันทำถูกไหม?
ฉันดูคำพูดของสจ็วตเซียร์เซียร์ " คิดในข้อมูล " และนำหนึ่งในแนวคิดจากนั้นเป็นหลักการออกแบบในเกมนี้ที่ฉันทำ ความแตกต่างคือเขาทำงานใน Clojure และฉันทำงานใน JavaScript ฉันเห็นความแตกต่างที่สำคัญระหว่างภาษาของเราในเรื่องนั้น: Clojure เป็นการเขียนโปรแกรมที่ใช้งานง่าย รัฐส่วนใหญ่ไม่เปลี่ยนรูป ฉันใช้ความคิดจากสไลด์ "ทุกอย่างคือแผนที่" (จาก 11 นาที, 6 วินาทีถึง> 29 นาที) บางสิ่งที่เขาพูดคือ: เมื่อใดก็ตามที่คุณเห็นฟังก์ชั่นที่ใช้อาร์กิวเมนต์ 2-3 ข้อคุณสามารถทำให้เป็นกรณีสำหรับเปลี่ยนเป็นแผนที่และเพิ่งผ่านแผนที่มามีข้อดีมากมายดังนี้: คุณไม่ต้องกังวลกับคำสั่งโต้แย้ง คุณไม่ต้องกังวลกับข้อมูลเพิ่มเติมใด ๆ หากมีกุญแจพิเศษนั่นไม่ใช่ความกังวลของเรา พวกเขาไหลผ่านพวกเขาไม่ได้ยุ่ง คุณไม่จำเป็นต้องกำหนดสคีมา ตรงข้ามกับการส่งผ่านวัตถุไม่มีการซ่อนข้อมูล แต่เขาทำให้กรณีที่การซ่อนข้อมูลสามารถทำให้เกิดปัญหาและ overrated: ประสิทธิภาพ ใช้งานง่าย ทันทีที่คุณสื่อสารผ่านเครือข่ายหรือข้ามกระบวนการคุณจะต้องให้ทั้งสองฝ่ายเห็นพ้องกับการแสดงข้อมูลต่อไป นั่นเป็นงานพิเศษที่คุณสามารถข้ามได้ถ้าคุณแค่ทำงานกับข้อมูล ส่วนใหญ่เกี่ยวข้องกับคำถามของฉัน นี่คือ 29 นาทีใน: "ทำให้ฟังก์ชั่นของคุณประกอบได้" นี่คือตัวอย่างโค้ดที่เขาใช้อธิบายแนวคิด: ;; Bad (defn complex-process [] …

10
การออกแบบที่เสนอของฉันมักจะแย่กว่าของเพื่อนร่วมงานของฉัน - ฉันจะดีขึ้นได้อย่างไร [ปิด]
ฉันเขียนโปรแกรมมาสองสามปีแล้วและโดยทั่วไปก็ดีเมื่อพูดถึงการแก้ไขปัญหาและการสร้างสคริปต์ขนาดเล็กถึงขนาดกลางอย่างไรก็ตามโดยทั่วไปฉันไม่ค่อยเก่งเรื่องการออกแบบโปรแกรมขนาดใหญ่ในลักษณะเชิงวัตถุ ไม่กี่คำถาม เมื่อเร็ว ๆ นี้เพื่อนร่วมงานที่มีประสบการณ์จำนวนเท่าฉันและฉันกำลังทำงานกับปัญหา ฉันทำงานกับปัญหาที่นานกว่าเขา แต่เขามาพร้อมกับทางออกที่ดีกว่าและในที่สุดเราก็จะใช้การออกแบบของเขา สิ่งนี้ส่งผลกระทบต่อฉันจริงๆ ฉันยอมรับว่าการออกแบบของเขาดีกว่า แต่ฉันต้องการออกแบบที่ดีพอ ๆ กับเขา ฉันยังคิดจะเลิกงาน ไม่แน่ใจว่าทำไม แต่ทันใดนั้นฉันก็รู้สึกกดดันบางอย่างเช่นรุ่นน้องคิดอย่างไรกับฉันและอื่น ๆ เป็นเรื่องปกติหรือไม่ หรือฉันคิดมากเกินไปในเรื่องนี้? งานของฉันเกี่ยวข้องกับการเขียนโปรแกรมใน Python ฉันพยายามอ่านซอร์สโค้ด แต่คุณคิดว่าฉันจะพัฒนาทักษะการออกแบบได้อย่างไร มีหนังสือหรือซอฟต์แวร์ดีๆสักเล่มที่ฉันควรศึกษาหรือไม่? โปรดให้ความกระจ่างแก่ฉัน ฉันจะขอขอบคุณสำหรับความช่วยเหลือของคุณ

4
ทำไมคอลเลกชัน Java จึงถูกนำไปใช้กับ“ วิธีการเสริม” ในอินเตอร์เฟส
ในระหว่างการนำไปใช้ครั้งแรกของฉันการขยายเฟรมเวิร์กคอลเลกชัน Java ฉันค่อนข้างประหลาดใจที่เห็นว่าอินเตอร์เฟสการรวบรวมมีวิธีการประกาศเป็นทางเลือก ผู้ดำเนินการคาดว่าจะโยน UnsupportedOperationExceptions หากไม่ได้รับการสนับสนุน สิ่งนี้ทำให้ฉันกลายเป็นตัวเลือกการออกแบบ API ที่แย่ทันที หลังจากอ่านหนังสือ "Effective Java" ที่ยอดเยี่ยมของ Joshua Bloch แล้วหลังจากเรียนรู้ว่าเขาอาจต้องรับผิดชอบต่อการตัดสินใจเหล่านี้ ฉันคิดว่าการประกาศอินเทอร์เฟซสองรายการ: คอลเลกชันและ MutableCollection ซึ่งขยายคอลเลกชันด้วยวิธีการ "ทางเลือก" จะทำให้รหัสลูกค้าที่บำรุงรักษาได้มากขึ้น มีบทสรุปที่ดีของปัญหาที่เป็นที่นี่ มีเหตุผลที่ดีหรือไม่ที่เลือกวิธีเสริมแทนที่จะใช้สองอินเตอร์เฟส

7
หากฟังก์ชั่นต้องทำการตรวจสอบโมฆะก่อนที่จะทำการออกแบบที่ไม่ดี
ดังนั้นฉันไม่รู้ว่านี่เป็นการออกแบบรหัสที่ดีหรือไม่ดีดังนั้นฉันจึงคิดว่าฉันควรถาม ฉันมักจะสร้างวิธีการที่ทำการประมวลผลข้อมูลที่เกี่ยวข้องกับคลาสและฉันมักจะตรวจสอบวิธีการต่าง ๆ มากมายเพื่อให้แน่ใจว่าฉันจะไม่ได้รับการอ้างอิงเป็นโมฆะหรือข้อผิดพลาดอื่น ๆ ก่อนถึงมือ สำหรับตัวอย่างพื้นฐานมาก: // fields and properties private Entity _someEntity; public Entity SomeEntity => _someEntity; public void AssignEntity(Entity entity){ _someEntity = entity; } public void SetName(string name) { if (_someEntity == null) return; //check to avoid null ref _someEntity.Name = name; label.SetText(_someEntity.Name); } ดังนั้นคุณจะเห็นการตรวจสอบ im สำหรับ …
67 c#  design  validation 

12
มีการตั้งค่าสถานะเพื่อระบุว่าเราควรผิดพลาดหรือไม่
ฉันเพิ่งเริ่มทำงานในที่ที่มีผู้พัฒนาอายุมาก (ประมาณ 50 ปีขึ้นไป) พวกเขาทำงานเกี่ยวกับแอพพลิเคชั่นที่สำคัญเกี่ยวกับการบินที่ระบบไม่สามารถลงได้ เป็นผลให้โปรแกรมเมอร์ที่มีอายุมากกว่ามีแนวโน้มที่จะรหัสด้วยวิธีนี้ เขามีแนวโน้มที่จะวางบูลีนในวัตถุเพื่อระบุว่าควรโยนข้อยกเว้นหรือไม่ ตัวอย่าง public class AreaCalculator { AreaCalculator(bool shouldThrowExceptions) { ... } CalculateArea(int x, int y) { if(x < 0 || y < 0) { if(shouldThrowExceptions) throwException; else return 0; } } } (ในโครงการของเราวิธีการอาจล้มเหลวเนื่องจากเราพยายามใช้อุปกรณ์เครือข่ายที่ไม่สามารถแสดงได้ในเวลาตัวอย่างพื้นที่เป็นเพียงตัวอย่างของการตั้งค่าสถานะข้อยกเว้น) สำหรับฉันนี่ดูเหมือนรหัสกลิ่น การเขียนการทดสอบหน่วยจะซับซ้อนกว่าเล็กน้อยเนื่องจากคุณต้องทดสอบการตั้งค่าสถานะข้อยกเว้นในแต่ละครั้ง นอกจากนี้หากมีสิ่งผิดปกติคุณไม่ต้องการรู้ทันทีหรือไม่? ไม่ควรเป็นความรับผิดชอบของผู้โทรที่จะกำหนดวิธีดำเนินการต่อ ตรรกะ / เหตุผลของเขาคือโปรแกรมของเราต้องการทำสิ่งหนึ่งแสดงข้อมูลให้ผู้ใช้ ข้อยกเว้นอื่นใดที่ไม่ได้ห้ามไม่ให้เราทำเช่นนั้นควรเพิกเฉย ฉันยอมรับว่าพวกเขาไม่ควรเพิกเฉย แต่ควรทำให้เกิดฟองและจัดการโดยบุคคลที่เหมาะสมและไม่จำเป็นต้องจัดการกับสถานะสำหรับสิ่งนั้น นี่เป็นวิธีที่ดีในการจัดการข้อยกเว้นหรือไม่ …

4
การผกผันของการควบคุมคืออะไรและฉันควรใช้เมื่อใด
ฉันกำลังออกแบบระบบใหม่และฉันต้องการทราบว่าการควบคุมกลับกัน (IOC) คืออะไรและที่สำคัญเมื่อใช้ จะต้องมีการใช้งานกับอินเตอร์เฟสหรือสามารถทำได้กับคลาส?

11
ชี้แจงหลักการความรับผิดชอบเดี่ยว
หลักการความรับผิดชอบเดี่ยวระบุว่าคลาสควรทำอย่างเดียวและอย่างเดียวเท่านั้น บางกรณีมีบาดแผลที่ค่อนข้างชัดเจน แม้ว่าคนอื่นจะยากเพราะสิ่งที่ดูเหมือน "สิ่งหนึ่ง" เมื่อดูในระดับที่เป็นนามธรรมอาจเป็นหลายสิ่งเมื่อดูในระดับที่ต่ำกว่า ฉันยังกลัวว่าหากหลักการความรับผิดชอบแบบเดี่ยวได้รับการยกย่องในระดับที่ต่ำกว่า decoupled มากเกินไปรหัส veravose รหัสราวีโอลี่ที่เส้นมากขึ้นจะใช้เวลาในการสร้างชั้นเรียนเล็ก ๆ สำหรับทุกอย่างและข้อมูลประปารอบกว่าการแก้ปัญหาที่เกิดขึ้นจริง คุณจะอธิบายความหมายของ "สิ่งหนึ่ง" ได้อย่างไร อะไรคือสัญญาณที่ชัดเจนว่าชั้นเรียนทำอะไรได้มากกว่า "สิ่งเดียว"?

14
MVC ต่อต้าน OOP ไม่ใช่หรือ
แนวคิดหลักที่อยู่เบื้องหลัง OOP คือการรวมข้อมูลและพฤติกรรมในเอนทิตีเดียว - วัตถุ ในการเขียนโปรแกรมแบบโพรซีเดอร์จะมีข้อมูลและอัลกอริธึมแยกต่างหากที่แก้ไขข้อมูล ในรูปแบบ Model-View-Controller ข้อมูลและตรรกะ / อัลกอริธึมจะถูกวางไว้ในเอนทิตีที่แตกต่างกันโมเดลและคอนโทรลเลอร์ตามลำดับ ในวิธีการ OOP ที่เทียบเท่ากันไม่ควรวางโมเดลและคอนโทรลเลอร์ไว้ในเอนทิตีแบบโลจิคัลเดียวกัน

6
ความแตกต่างระหว่างระดับบริการและระดับผู้ช่วย [ปิด]
ฉันต้องการที่จะรู้ว่าสิ่งที่แตกต่างชั้นบริการจากระดับยูทิลิตี้หรือชั้นผู้ช่วย? ชั้นเรียนที่มีวิธีการพื้นฐานเรียก dao เป็นบริการหรือไม่ การใช้คลาส Helper ไม่เป็นการละเมิด SRP หรือไม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.