มีรูปแบบการออกแบบเพื่อลบความต้องการตรวจสอบค่าสถานะหรือไม่


28

ฉันจะบันทึกส่วนของข้อมูลสตริงในฐานข้อมูล ฉันมีการกำหนดค่าระดับโลกสองแบบ:

  • การเข้ารหัส
  • การอัด

สิ่งเหล่านี้สามารถเปิดใช้งานหรือปิดการใช้งานโดยใช้การกำหนดค่าในลักษณะที่เปิดใช้งานเพียงอย่างเดียวเท่านั้นทั้งสองถูกเปิดใช้งานหรือทั้งสองอย่างถูกปิดใช้งาน

การใช้งานปัจจุบันของฉันคือ:

if (encryptionEnable && !compressEnable) {
    encrypt(data);
} else if (!encryptionEnable && compressEnable) {
    compress(data);
} else if (encryptionEnable && compressEnable) {
    encrypt(compress(data));
} else {
  data;
}

ฉันกำลังคิดเกี่ยวกับลวดลายมัณฑนากร มันเป็นตัวเลือกที่ถูกต้องหรืออาจเป็นทางเลือกที่ดีกว่า


5
เกิดอะไรขึ้นกับสิ่งที่คุณมีอยู่ในปัจจุบัน? ข้อกำหนดมีแนวโน้มที่จะเปลี่ยนแปลงสำหรับฟังก์ชันนี้หรือไม่ IE มีแนวโน้มที่จะมีifคำสั่งใหม่หรือไม่?
Darren Young

ไม่ฉันกำลังดูโซลูชันอื่น ๆ เพื่อปรับปรุงรหัส
Damith Ganegoda

46
คุณกำลังจะย้อนหลังนี้ คุณไม่พบรูปแบบแล้วเขียนรหัสเพื่อให้พอดีกับรูปแบบ คุณเขียนรหัสให้เหมาะกับความต้องการของคุณแล้วเลือกใช้รูปแบบเพื่ออธิบายรหัสของคุณ
การแข่งขัน Lightness กับ Monica

1
โปรดทราบว่าคุณเชื่อว่าคำถามของคุณซ้ำกับคำถามนี้ดังนั้นในฐานะผู้ถามคุณมีตัวเลือก "แทนที่" ที่จะเปิดใหม่เมื่อไม่นานมานี้และปิดอย่างเดียวอย่างเช่น ฉันทำอย่างนั้นกับคำถามของตัวเองและมันก็ใช้งานได้เหมือนมีเสน่ห์ นี่คือวิธีที่ฉันทำ 3 ขั้นตอนง่ายๆ - ความแตกต่างเพียงอย่างเดียวกับ "คำแนะนำ" ของฉันคือเนื่องจากคุณมีตัวแทนน้อยกว่า 3K คุณจะต้องผ่านกล่องโต้ตอบการตั้งค่าสถานะเพื่อไปที่ตัวเลือก "ซ้ำ"
gnat

8
@LightnessRacesinOrbit: มีความจริงบางอย่างในสิ่งที่คุณพูด แต่ก็สมเหตุสมผลดีที่จะถามว่ามีวิธีที่ดีกว่าในการจัดโครงสร้างโค้ดของตัวเองหรือไม่ (ถึงกระนั้นฉันก็เห็นด้วยว่ามันเป็นปัญหาเล็กน้อยของ XY ที่จะขอรูปแบบการออกแบบเมื่อสิ่งที่คุณต้องการคือการออกแบบที่อาจหรือไม่อาจปฏิบัติตามรูปแบบที่รู้จักกันดีอย่างเคร่งครัด) นอกจากนี้มันถูกต้องตามกฎหมายสำหรับ ส่งผลกระทบต่อรหัสของคุณเล็กน้อยซึ่งหากคุณใช้รูปแบบที่รู้จักกันดีก็มักจะทำให้ชื่อส่วนประกอบของคุณเหมาะสม
ruakh

คำตอบ:


15

เมื่อออกแบบรหัสคุณมีสองตัวเลือก

  1. เพิ่งจะทำมันเสร็จแล้วซึ่งในกรณีนี้การแก้ปัญหาใด ๆ ก็จะใช้ได้ผลสำหรับคุณ
  2. เป็นคนคล่องแคล่วและออกแบบโซลูชั่นที่ใช้ประโยชน์จากนิสัยใจคอของภาษาและอุดมการณ์ของมัน (ภาษา OO ในกรณีนี้ - การใช้ polymorphism เป็นเครื่องมือในการตัดสินใจ)

ฉันจะไม่มุ่งความสนใจไปที่หนึ่งในสองคนแรกเพราะไม่มีอะไรจะพูด หากคุณแค่อยากให้มันใช้งานได้คุณสามารถทิ้งรหัสไว้ได้

แต่จะเกิดอะไรขึ้นถ้าคุณเลือกที่จะทำแบบอวดความคิดและแก้ไขปัญหากับรูปแบบการออกแบบในแบบที่คุณต้องการ

คุณสามารถดูกระบวนการต่อไปนี้:

เมื่อออกแบบรหัส OO ส่วนใหญ่ifที่อยู่ในรหัสไม่จำเป็นต้องอยู่ที่นั่น โดยธรรมชาติหากคุณต้องการเปรียบเทียบสองประเภทสเกลาร์เช่นints หรือfloats คุณมีโอกาสที่จะมีifแต่ถ้าคุณต้องการเปลี่ยนขั้นตอนตามการกำหนดค่าคุณสามารถใช้polymorphismเพื่อบรรลุสิ่งที่คุณต้องการย้ายการตัดสินใจ ( ifs) จากเหตุผลทางธุรกิจของคุณไปยังสถานที่ที่วัตถุ instantiated - เพื่อโรงงาน

ณ ตอนนี้กระบวนการของคุณสามารถผ่าน 4 เส้นทางแยก:

  1. dataไม่มีการเข้ารหัสหรือบีบอัด (โทรอะไรกลับมาdata)
  2. dataถูกบีบอัด (โทรcompress(data)และส่งคืน)
  3. dataถูกเข้ารหัส (โทรencrypt(data)และส่งคืน)
  4. dataถูกบีบอัดและเข้ารหัส (โทรencrypt(compress(data))แล้วส่งคืน)

เพียงแค่มองไปที่ 4 เส้นทางคุณจะพบปัญหา

คุณมีหนึ่งกระบวนการที่เรียก 3 (ในทางทฤษฎี 4 ถ้าคุณนับว่าไม่เรียกอะไรเป็นหนึ่ง) วิธีการต่าง ๆ ที่จัดการข้อมูลแล้วส่งคืน เมธอดมีชื่อแตกต่างกันเรียกว่าพับลิก API สาธารณะ (วิธีที่วิธีการสื่อสารพฤติกรรมของพวกเขา)

การใช้รูปแบบอะแดปเตอร์เราสามารถแก้ไขชื่อ colision (เราสามารถรวม API สาธารณะ) ที่เกิดขึ้นได้ กล่าวง่ายๆว่าอะแดปเตอร์ช่วยให้อินเตอร์เฟสที่เข้ากันไม่ได้ทั้งสองทำงานร่วมกันได้ นอกจากนี้อะแดปเตอร์ยังทำงานด้วยการกำหนดอินเทอร์เฟซของอะแดปเตอร์ใหม่ซึ่งคลาสที่พยายามรวมการใช้ API ของตนเข้าด้วยกัน

นี่ไม่ใช่ภาษาที่เป็นรูปธรรม มันเป็นวิธีการทั่วไปคำหลักใด ๆ ที่มีเพื่อแสดงว่าอาจเป็นรูปแบบใด ๆ ในภาษาเช่น C # คุณสามารถแทนที่ด้วย generics ( <T>)

ฉันจะสมมติว่าตอนนี้คุณสามารถมีสองคลาสที่รับผิดชอบการบีบอัดและการเข้ารหัส

class Compression
{
    Compress(data : any) : any { ... }
}

class Encryption
{
    Encrypt(data : any) : any { ... }
}

ในโลกธุรกิจแม้แต่คลาสที่เฉพาะเจาะจงเหล่านี้มีแนวโน้มที่จะถูกแทนที่ด้วยอินเทอร์เฟซเช่นclassคำหลักจะถูกแทนที่ด้วยinterface(คุณควรจัดการกับภาษาเช่น C #, Java และ / หรือ PHP) หรือclassคำหลักจะยังคงอยู่CompressและEncryptวิธีการที่จะถูกกำหนดเป็นเสมือนจริงคุณควรรหัสใน C ++

ในการสร้างอะแดปเตอร์เรากำหนดอินเตอร์เฟสทั่วไป

interface DataProcessing
{
    Process(data : any) : any;
}

จากนั้นเราจะต้องจัดทำอินเทอร์เฟซให้มีประโยชน์

// when neither encryption nor compression is enabled
class DoNothingAdapter : DataProcessing
{
    public Process(data : any) : any
    {
        return data;
    }
}

// when only compression is enabled
class CompressionAdapter : DataProcessing
{
    private compression : Compression;

    public Process(data : any) : any
    {
        return this.compression.Compress(data);
    }
}

// when only encryption is enabled
class EncryptionAdapter : DataProcessing
{
    private encryption : Encryption;

    public Process(data : any) : any
    {
        return this.encryption.Encrypt(data);
    }
}

// when both, compression and encryption are enabled
class CompressionEncryptionAdapter : DataProcessing
{
    private compression : Compression;
    private encryption : Encryption;

    public Process(data : any) : any
    {
        return this.encryption.Encrypt(
            this.compression.Compress(data)
        );
    }
}

ด้วยการทำเช่นนี้คุณจะจบลงด้วย 4 คลาสซึ่งแต่ละคนทำสิ่งที่แตกต่างกันโดยสิ้นเชิง แต่แต่ละคลาสก็มี API สาธารณะเดียวกัน Processวิธี

ในตรรกะทางธุรกิจของคุณที่คุณจัดการกับการตัดสินใจที่ไม่มี / การเข้ารหัส / การบีบอัด / ทั้งสองคุณจะออกแบบวัตถุของคุณเพื่อให้มันขึ้นอยู่กับDataProcessingอินเทอร์เฟซที่เราออกแบบมาก่อน

class DataService
{
    private dataProcessing : DataProcessing;

    public DataService(dataProcessing : DataProcessing)
    {
        this.dataProcessing = dataProcessing;
    }
}

กระบวนการนั้นอาจจะง่ายอย่างนี้:

public ComplicatedProcess(data : any) : any
{
    data = this.dataProcessing.Process(data);

    // ... perhaps work with the data

    return data;
}

ไม่มีเงื่อนไขเพิ่มเติม ชั้นDataServiceไม่มีความคิดว่าจะทำอย่างไรกับข้อมูลจริง ๆ เมื่อมันถูกส่งไปยังdataProcessingสมาชิกและไม่สนใจจริง ๆ มันเป็นความรับผิดชอบของมัน

เป็นการดีที่คุณจะมีการทดสอบหน่วยการทดสอบ 4 ชั้นอะแดปเตอร์ที่คุณสร้างขึ้นเพื่อให้แน่ใจว่าพวกเขาทำงานคุณทำแบบทดสอบของคุณ และถ้าพวกเขาผ่านคุณสามารถมั่นใจได้ว่าพวกเขาจะทำงานไม่ว่าคุณจะเรียกพวกเขาในรหัสของคุณ

ดังนั้นทำอย่างนี้ฉันจะไม่ifอยู่ในรหัสของฉันอีกต่อไป?

ไม่คุณมีโอกาสน้อยที่จะมีเงื่อนไขในตรรกะทางธุรกิจของคุณ แต่พวกเขายังคงต้องอยู่ที่ไหนซักแห่ง สถานที่คือโรงงานของคุณ

และนี่คือสิ่งที่ดี คุณแยกความกังวลของการสร้างและใช้รหัสจริง หากคุณทำให้โรงงานของคุณเชื่อถือได้ (ใน Java คุณสามารถใช้งานได้กับ Google เช่นกรอบการทำงานของGuice ) ในตรรกะทางธุรกิจของคุณคุณไม่ต้องกังวลกับการเลือกชั้นเรียนที่ถูกต้อง เพราะคุณรู้ว่าโรงงานของคุณทำงานและจะส่งมอบสิ่งที่ถูกถาม

จำเป็นต้องมีคลาสอินเทอร์เฟซและอื่น ๆ ทั้งหมดหรือไม่

สิ่งนี้นำเรากลับไปสู่จุดเริ่มต้น

ใน OOP หากคุณเลือกเส้นทางที่จะใช้ polymorphism ต้องการใช้รูปแบบการออกแบบต้องการใช้ประโยชน์จากคุณสมบัติของภาษาและ / หรือต้องการทำตามทุกอย่างเป็นอุดมการณ์ของวัตถุ และจากนั้นตัวอย่างนี้ไม่ได้แสดงโรงงานทั้งหมดที่คุณต้องการและถ้าคุณต้องปรับโครงสร้างCompressionและEncryptionคลาสและทำให้อินเทอร์เฟซแทนคุณต้องรวมการใช้งานของพวกเขาด้วย

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

หากคุณต้องการที่จะได้รับมันกระทำได้อย่างรวดเร็วและคุณสามารถคว้าแก้ปัญหา Ixrec ของที่อย่างน้อยมีการจัดการที่จะกำจัดelse ifและบล็อกซึ่งในความคิดของฉันแม้ตาดเลวร้ายยิ่งกว่าธรรมดาelseif

คำนึงถึงนี่เป็นวิธีของฉันในการออกแบบ OO ที่ดี การเข้ารหัสไปยังอินเทอร์เฟซมากกว่าการนำไปใช้งานนี่เป็นวิธีที่ฉันทำในช่วงไม่กี่ปีที่ผ่านมาและเป็นวิธีที่ฉันคุ้นเคยกับมันมากที่สุด

ฉันชอบการเขียนโปรแกรมแบบ if-less มากขึ้นและจะซาบซึ้งมากขึ้นถึงวิธีแก้ปัญหาที่ยาวกว่ารหัส 5 บรรทัด มันเป็นวิธีที่ฉันคุ้นเคยกับการออกแบบโค้ดและฉันอ่านมันได้อย่างสบายใจ


อัปเดต 2:มีการพูดคุยอย่างฉับพลันเกี่ยวกับโซลูชันเวอร์ชันแรกของฉัน การสนทนาส่วนใหญ่เกิดจากฉันซึ่งฉันขอโทษ

ฉันตัดสินใจที่จะแก้ไขคำตอบในลักษณะที่เป็นวิธีหนึ่งในการดูวิธีแก้ไขปัญหา แต่ไม่ใช่วิธีเดียว ฉันยังลบส่วนมัณฑนากรซึ่งฉันหมายถึงส่วนหน้าแทนซึ่งในที่สุดฉันก็ตัดสินใจแยกออกอย่างสมบูรณ์เพราะอะแดปเตอร์เป็นรูปแบบด้านหน้า


28
ฉันไม่ได้ลงคะแนน แต่เหตุผลอาจเป็นจำนวนไร้สาระของคลาส / อินเทอร์เฟซใหม่ที่จะทำสิ่งที่รหัสต้นฉบับทำใน 8 บรรทัด (และคำตอบอื่นทำใน 5) ในความคิดของฉันสิ่งเดียวที่ทำให้สำเร็จคือการเพิ่มช่วงการเรียนรู้สำหรับรหัส
Maurycy

6
@Maurycy สิ่งที่ OP ถามคือพยายามหาวิธีแก้ปัญหาของเขาโดยใช้รูปแบบการออกแบบทั่วไปหากมีวิธีการแก้ปัญหาอยู่ ทางออกของฉันยาวกว่ารหัสของเขาหรือ Ixrec หรือไม่? มันคือ. ฉันยอมรับว่า วิธีการแก้ปัญหาของฉันแก้ปัญหาของเขาโดยใช้รูปแบบการออกแบบและตอบคำถามของเขาและยังลบทั้งหมดที่จำเป็นจากกระบวนการ? มันทำ Ixrec ไม่ได้
Andy

26
ฉันเชื่อว่าการเขียนรหัสที่ชัดเจนน่าเชื่อถือรัดกุมนักแสดงและการบำรุงรักษาเป็นวิธีที่จะไป ถ้าฉันมีเงินดอลลาร์สำหรับทุกครั้งที่มีคนอ้างถึง SOLID หรืออ้างถึงรูปแบบซอฟต์แวร์โดยไม่ต้องระบุเป้าหมายและเหตุผลของพวกเขาอย่างชัดเจนฉันจะเป็นคนร่ำรวย
Robert Harvey

12
ฉันคิดว่าฉันมีสองประเด็นที่ฉันเห็นที่นี่ ครั้งแรกคือCompressionและEncryptionอินเทอร์เฟซดูเหมือนเหลือเฟือโดยสิ้นเชิง ฉันไม่แน่ใจว่าคุณกำลังบอกว่าพวกเขามีความจำเป็นต่อกระบวนการตกแต่งหรือหมายความว่าพวกเขาเป็นตัวแทนของแนวคิดที่แยกออกมา ปัญหาที่สองคือการสร้างคลาสเหมือนCompressionEncryptionDecoratorนำไปสู่การระเบิดแบบ combinatorial เช่นเดียวกับเงื่อนไขของ OP ฉันยังไม่เห็นรูปแบบการตกแต่งภายในอย่างชัดเจนเพียงพอในรหัสที่แนะนำ
cbojar

5
การถกเถียงเรื่อง SOLID vs. simple นั้นเป็นประเด็นที่ขาดหายไป: รหัสนี้ไม่ใช่และมันก็ไม่ได้ใช้รูปแบบการตกแต่งภายใน รหัสไม่ได้เป็นแบบโซลิดโดยอัตโนมัติเพียงเพราะมันใช้อินเตอร์เฟซเป็นจำนวนมาก การฉีดการพึ่งพาของอินเทอร์เฟซ DataProcessing ค่อนข้างดี ทุกอย่างอื่นไม่จำเป็น SOLID เป็นข้อกังวลระดับสถาปัตยกรรมที่มุ่งเน้นการจัดการการเปลี่ยนแปลงที่ดี OP ไม่ให้ข้อมูลเกี่ยวกับสถาปัตยกรรมของเขาหรือวิธีที่เขาคาดหวังว่ารหัสของเขาจะเปลี่ยนแปลงดังนั้นเราจึงไม่สามารถแม้แต่จะพูดคุยเกี่ยวกับ SOLID ในคำตอบ
Carl Leth

120

ปัญหาเดียวที่ฉันเห็นกับรหัสปัจจุบันของคุณคือความเสี่ยงของการระเบิดแบบ combinatorial เมื่อคุณเพิ่มการตั้งค่าเพิ่มเติมซึ่งสามารถลดได้อย่างง่ายดายโดยการจัดโครงสร้างรหัสให้เป็นดังนี้:

if(compressEnable){
  data = compress(data);
}
if(encryptionEnable) {
  data = encrypt(data);
}
return data;

ฉันไม่ทราบว่า "รูปแบบการออกแบบ" หรือ "สำนวน" ใด ๆ ที่อาจถือเป็นตัวอย่างของ


18
@DamithGanegoda Nope ถ้าคุณอ่านรหัสของฉันอย่างระมัดระวังคุณจะเห็นว่ามันทำแบบเดียวกันในกรณีนั้น นั่นเป็นเหตุผลว่าทำไมelseระหว่างฉันทั้งสองถ้างบและทำไมฉันกำหนดให้ในdataแต่ละครั้ง หากแฟล็กทั้งสองเป็นจริงแล้วบีบอัด () ได้รับการดำเนินการแล้วเข้ารหัส () ได้รับการดำเนินการเกี่ยวกับผลของการบีบอัด () เช่นเดียวกับที่คุณต้องการ
Ixrec

14
@DavidPacker ในทางเทคนิคแล้วจะทำทุกคำสั่งถ้าในทุกภาษาการเขียนโปรแกรม ฉันไปเพื่อความเรียบง่ายเนื่องจากดูเหมือนว่าปัญหาที่คำตอบง่าย ๆ เหมาะสม โซลูชันของคุณก็ใช้ได้เช่นกัน แต่โดยส่วนตัวแล้วฉันจะบันทึกไว้เมื่อฉันมีสถานะบูลีนมากกว่าสองอันที่ต้องกังวล
Ixrec

15
@DavidPacker: ถูกต้องไม่ได้ถูกกำหนดโดยวิธีการที่ดีรหัสปฏิบัติตามแนวทางบางอย่างโดยผู้เขียนบางคนเกี่ยวกับอุดมการณ์การเขียนโปรแกรมบางอย่าง ถูกต้องคือ "ทำรหัสทำสิ่งที่ควรทำและนำไปใช้ในระยะเวลาที่เหมาะสม" ถ้ามันสมเหตุสมผลที่จะทำในสิ่งที่ "ผิด" แล้ววิธีที่ผิดนั้นเป็นวิธีที่ถูกต้องเพราะเวลาคือเงิน
whatsisname

9
@DavidPacker: ถ้าฉันอยู่ในตำแหน่ง OP และถามคำถามนั้นความคิดเห็นของ Lightness Race ใน Orbit คือสิ่งที่ฉันต้องการจริงๆ "การหาวิธีการแก้ปัญหาโดยใช้รูปแบบการออกแบบ" เริ่มต้นจากความผิดพลาดแล้ว
whatsisname

6
@DavidPacker จริงๆแล้วถ้าคุณอ่านคำถามให้ละเอียดยิ่งขึ้นมันไม่ได้ยืนยันในรูปแบบ มันกล่าวว่า"ฉันกำลังคิดเกี่ยวกับรูปแบบของมัณฑนากรมันเป็นตัวเลือกที่ถูกต้องหรืออาจเป็นทางเลือกที่ดีกว่าหรือไม่" . คุณพูดประโยคแรกในคำพูดของฉัน แต่ไม่ใช่ประโยคที่สอง คนอื่นเอาแนวทางที่ไม่มันไม่ใช่ทางเลือกที่ถูกต้อง คุณไม่สามารถอ้างได้ว่ามีเพียงคุณเท่านั้นที่ตอบคำถาม
Jon Bentley

12

ฉันเดาว่าคำถามของคุณดูไม่เหมาะกับการใช้งานจริงซึ่งในกรณีนี้คำตอบของ lxrec นั้นถูกต้อง แต่เพื่อเรียนรู้เกี่ยวกับรูปแบบการออกแบบ

เห็นได้ชัดว่ารูปแบบคำสั่งเป็นปัญหามากเกินไปสำหรับปัญหาเล็ก ๆ น้อย ๆ ตามที่คุณเสนอ แต่เพื่อภาพประกอบที่นี่:

public interface Command {
    public String transform(String s);
}

public class CompressCommand implements Command {
    @Override
    public String transform(String s) {
        String compressedString=null;
        //Compression code here
        return compressedString;
    }
}

public class EncryptCommand implements Command {
    @Override
    public String transform(String s) {
        String EncrytedString=null;
        // Encryption code goes here
        return null;
    }

}

public class Test {
    public static void main(String[] args) {
        List<Command> commands = new ArrayList<Command>();
        commands.add(new CompressCommand());
        commands.add(new EncryptCommand()); 
        String myString="Test String";
        for (Command c: commands){
            myString = c.transform(myString);
        }
        // now myString can be stored in the database
    }
}

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

เห็นได้ชัดว่าเงื่อนไขจะสิ้นสุดในโรงงานบางชนิดที่รวมรายการคำสั่งไว้ด้วยกัน

แก้ไขสำหรับความคิดเห็นของ @ texacre:

มีหลายวิธีในการหลีกเลี่ยงถ้าเงื่อนไขในส่วน Creational ของการแก้ปัญหาจะลองยกตัวอย่างเช่นแอป GUI เดสก์ทอป คุณสามารถมีช่องทำเครื่องหมายสำหรับตัวเลือกการบีบอัดและเข้ารหัส ในon clicกรณีที่ช่องทำเครื่องหมายเหล่านั้นคุณยกตัวอย่างคำสั่งที่เกี่ยวข้องและเพิ่มลงในรายการหรือลบออกจากรายการหากคุณยกเลิกการเลือกตัวเลือก


หากคุณไม่สามารถให้ตัวอย่างของ "โรงงานบางชนิดที่รวมรายการคำสั่ง" เข้าด้วยกันโดยไม่มีโค้ดที่ดูเหมือนคำตอบของ Ixrec ดังนั้น IMO จึงไม่ตอบคำถาม นี่เป็นวิธีที่ดีกว่าในการใช้ฟังก์ชันการบีบอัดและเข้ารหัส แต่ไม่ใช่วิธีการหลีกเลี่ยงการตั้งค่าสถานะ
thexacre

@thexacre ฉันเพิ่มตัวอย่าง
Tulains Córdova

ดังนั้นในฟังเหตุการณ์ช่องทำเครื่องหมายของคุณคุณมี "ถ้า checkbox.ticked แล้วเพิ่มคำสั่ง"? มันดูเหมือนว่าผมชอบคุณเพียงแค่สับธงถ้างบรอบ ...
thexacre

@thexacre ไม่ผู้ฟังหนึ่งคนสำหรับแต่ละช่องทำเครื่องหมาย ในเหตุการณ์คลิกเพียงcommands.add(new EncryptCommand()); หรือcommands.add(new CompressCommand());ตามลำดับ
Tulains Córdova

สิ่งที่เกี่ยวกับการจัดการการยกเลิกการทำเครื่องหมายในกล่อง? ในเกือบทุกภาษา / ชุดเครื่องมือ UI ที่ฉันพบคุณยังคงต้องตรวจสอบสถานะของช่องทำเครื่องหมายในฟังเหตุการณ์ ฉันยอมรับว่านี่เป็นรูปแบบที่ดีกว่า แต่ก็ไม่จำเป็นต้องหลีกเลี่ยงโดยทั่วไปหากมีการทำเครื่องหมายบางสิ่ง
thexacre

7

ฉันคิดว่า "รูปแบบการออกแบบ" นั้นเน้นไปที่ "รูปแบบ oo" โดยไม่จำเป็นและหลีกเลี่ยงแนวคิดที่ง่ายกว่ามาก สิ่งที่เรากำลังพูดถึงที่นี่คือไปป์ไลน์ข้อมูล (ง่าย)

ฉันจะลองทำมันใน clojure ภาษาอื่นใดที่ฟังก์ชั่นชั้นหนึ่งก็อาจใช้ได้เช่นกัน บางทีฉันอาจเป็นตัวอย่าง C # ในภายหลัง แต่มันก็ไม่ดี วิธีของฉันในการแก้ปัญหานี้จะเป็นขั้นตอนต่อไปนี้พร้อมคำอธิบายบางอย่างสำหรับผู้ที่ไม่สวมรองเท้า:

1. แสดงชุดของการแปลง

(def transformations { :encrypt  (fn [data] ... ) 
                       :compress (fn [data] ... )})

นี่คือแผนที่เช่นตารางการค้นหา / พจนานุกรม / อะไรก็ตามจากคำหลักไปยังฟังก์ชั่น ตัวอย่างอื่น (คำสำคัญกับสตริง):

(def employees { :A1 "Alice" 
                 :X9 "Bob"})

(employees :A1) ; => "Alice"
(:A1 employees) ; => "Alice"

ดังนั้นการเขียน(transformations :encrypt)หรือ(:encrypt transformations)จะส่งกลับฟังก์ชั่นการเข้ารหัส ( (fn [data] ... )เป็นเพียงฟังก์ชั่นแลมบ์ดา)

2. รับตัวเลือกเป็นลำดับของคำหลัก:

(defn do-processing [options data] ;function definition
  ...)

(do-processing [:encrypt :compress] data) ;call to function

3. กรองการแปลงทั้งหมดโดยใช้ตัวเลือกที่ให้มา

(let [ transformations-to-run (map transformations options)] ... )

ตัวอย่าง:

(map employees [:A1]) ; => ["Alice"]
(map employees [:A1 :X9]) ; => ["Alice", "Bob"]

4. รวมฟังก์ชั่นเป็นหนึ่ง:

(apply comp transformations-to-run)

ตัวอย่าง:

(comp f g h) ;=> f(g(h()))
(apply comp [f g h]) ;=> f(g(h()))

5. จากนั้นเข้าด้วยกัน:

(def transformations { :encrypt  (fn [data] ... ) 
                       :compress (fn [data] ... )})

(defn do-processing [options data]
  (let [transformations-to-run (map transformations options)
        selected-transformations (apply comp transformations-to-run)] 
    (selected-transformations data)))

(do-processing [:encrypt :compress])

การเปลี่ยนแปลงเท่านั้นหากเราต้องการเพิ่มฟังก์ชั่นใหม่พูดว่า "debug-print" มีดังต่อไปนี้:

(def transformations { :encrypt  (fn [data] ... ) 
                       :compress (fn [data] ... )
                       :debug-print (fn [data] ...) }) ;<--- here to add as option

(defn do-processing [options data]
  (let [transformations-to-run (map transformations options)
        selected-transformations (apply comp transformations-to-run)] 
    (selected-transformations data)))

(do-processing [:encrypt :compress :debug-print]) ;<-- here to use it
(do-processing [:compress :debug-print]) ;or like this
(do-processing [:encrypt]) ;or like this

funcs บรรจุอย่างไรรวมฟังก์ชั่นที่จำเป็นต้องนำมาใช้โดยไม่ต้องใช้ชุดของงบถ้าในทางใดทางหนึ่ง?
thexacre

แถวfuncs-to-run-here (map options funcs)กำลังทำการกรองดังนั้นการเลือกชุดฟังก์ชั่นที่จะใช้ บางทีฉันควรจะปรับปรุงคำตอบและเข้าไปดูรายละเอียดเพิ่มเติม
NiklasJ

5

[หลัก, คำตอบของฉันคือการติดตามไปที่คำตอบโดย @Ixrec ดังกล่าวข้างต้น ]

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

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

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


1

วิธีหนึ่งในการทำเช่นนี้ในสกาล่าคือ:

val handleCompression: AnyRef => AnyRef = data => if (compressEnable) compress(data) else data
val handleEncryption: AnyRef => AnyRef = data => if (encryptionEnable) encrypt(data) else data
val handleData = handleCompression andThen handleEncryption
handleData(data)

การใช้รูปแบบมัณฑนากรเพื่อให้บรรลุเป้าหมายข้างต้น (การแยกตรรกะการประมวลผลส่วนบุคคลและวิธีที่พวกเขาเชื่อมต่อกัน) จะละเอียดเกินไป

ในกรณีที่คุณต้องการรูปแบบการออกแบบเพื่อให้บรรลุเป้าหมายการออกแบบเหล่านี้ในกระบวนทัศน์การเขียนโปรแกรม OO ภาษาเชิงฟังก์ชันให้การสนับสนุนแบบดั้งเดิมโดยใช้ฟังก์ชั่นเป็นพลเมืองชั้นหนึ่ง (บรรทัดที่ 1 และ 2 ในรหัส) และองค์ประกอบการทำงาน (บรรทัดที่ 3)


ทำไมสิ่งนี้ถึงดีกว่าหรือแย่กว่าวิธีการของ OP และ / หรือคุณคิดอย่างไรเกี่ยวกับแนวคิดของ OP ในการใช้รูปแบบมัณฑนากร?
Kasper van den Berg

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