การทำให้เป็นอันดับและการดีซีเรียลไลเซชั่นควรเป็นความรับผิดชอบของชั้นเรียนหรือไม่


16

ขณะนี้ฉันอยู่ในขั้นตอนการออกแบบ (อีกครั้ง) ของคลาสรุ่นต่างๆของแอปพลิเคชัน C # .NET (โมเดลดังใน M ของ MVC) คลาสโมเดลมีข้อมูลพฤติกรรมและความสัมพันธ์ซึ่งได้รับการออกแบบมาเป็นอย่างดี ฉันเขียนแบบจำลองใหม่จาก Python เป็น C #

ใน Python model ฉันคิดว่าฉันเห็นหูด แต่ละรุ่นรู้วิธีการทำให้เป็นอันดับตัวเองและตรรกะการทำให้เป็นอันดับไม่มีส่วนเกี่ยวข้องกับพฤติกรรมที่เหลือของคลาสใด ๆ ตัวอย่างเช่นลองนึกภาพ:

  • Imageชั้นเรียนด้วย.toJPG(String filePath) .fromJPG(String filePath)วิธีการ
  • ImageMetaDataชั้นเรียนด้วย.toString()และ.fromString(String serialized)วิธีการ

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

มันเป็นเรื่องธรรมดาสำหรับชั้นเรียนหรือไม่ที่จะรู้วิธีการทำให้เป็นอันดับและทำให้เสียความเป็นตัวของตัวเอง? หรือฉันไม่มีรูปแบบทั่วไป

คำตอบ:


16

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

public class Image
{
    public void toJPG(String filePath) { ... }

    public Image fromJPG(String filePath) { ... }
}

แต่ถ้าคุณต้องการทำให้เป็นอนุกรมจาก / PNG และ GIF ตอนนี้ชั้นจะกลายเป็น

public class Image
{
    public void toJPG(String filePath) { ... }

    public Image fromJPG(String filePath) { ... }

    public void toPNG(String filePath) { ... }

    public Image fromPNG(String filePath) { ... }

    public void toGIF(String filePath) { ... }

    public Image fromGIF(String filePath) { ... }
}

แต่โดยทั่วไปแล้วฉันต้องการใช้รูปแบบที่คล้ายกับสิ่งต่อไปนี้:

public interface ImageSerializer
{
    void serialize(Image src, Stream outputStream);

    Image deserialize(Stream inputStream);
}

public class JPGImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

public class PNGImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

public class GIFImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

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

public class Image
{
    public void serializeTo(ImageSerializer serializer, Stream outputStream)
    {
        serializer.serialize(this.pixelData, outputStream);
    }

    public void deserializeFrom(ImageSerializer serializer, Stream inputStream)
    {
        this.pixelData = serializer.deserialize(inputStream);
    }
}

นี่เป็นตัวอย่างทั่วไปมากขึ้นเนื่องจากภาพมักจะมีข้อมูลเมตาที่สอดคล้องกับมัน สิ่งต่าง ๆ เช่นระดับการบีบอัด colorspace ฯลฯ ซึ่งอาจทำให้กระบวนการมีความซับซ้อน


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

จุดที่ดีมาก ฉันกำลังคิดเกี่ยวกับสิ่งนั้น แต่มีผายลมในสมอง ฉันจะอัปเดตรหัส
Zymus

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

ในขณะที่ฉันเข้าใจว่าคุณมาจากไหนฉันรู้สึกว่ามันไม่ใช่ปัญหาด้วยเหตุผลสองประการ หากเป็นรูปแบบภาพที่มีอยู่โอกาสที่ Serializer รู้อยู่แล้วว่าจะจัดการกับระดับการบีบอัดได้อย่างไรและถ้าเป็นรูปแบบใหม่คุณจะต้องเขียนมันต่อไป ทางออกหนึ่งคือการโอเวอร์โหลดวิธีการบางอย่างเช่นvoid serialize(Image image, Stream outputStream, SerializerSettings settings);จากนั้นเป็นเพียงกรณีของการต่อเชื่อมการบีบอัดและเมตาดาต้าตรรกะที่มีอยู่กับวิธีการใหม่
ไซมัส

3

การทำให้เป็นอันดับเป็นปัญหาสองส่วน:

  1. ความรู้เกี่ยวกับวิธีการ instantiate ชั้นโครงสร้าง aka
  2. ความรู้เกี่ยวกับวิธีการยังคงมีอยู่ / โอนข้อมูลที่จำเป็นในการยกตัวอย่างชั้นเรียนaka กลศาสตร์

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

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

ในบริบทของ IPC คุณสามารถแยกชั้นของคุณจากนั้นเลือกประกาศข้อมูลที่จำเป็นสำหรับการทำให้เป็นอันดับ (โดยการเพิ่มความคิดเห็น / คุณสมบัติ) จากนั้นอัลกอริทึมการทำให้เป็นอันดับของคุณสามารถตัดสินใจได้ว่าจะใช้ JSON, Google Protocol Buffers หรือ XML สำหรับการทำให้เป็นอนุกรม มันยังสามารถตัดสินใจได้ว่าจะใช้ Jackson parser หรือ parser ที่คุณกำหนดเอง - มีตัวเลือกมากมายที่คุณจะได้รับเมื่อคุณออกแบบในแบบแยกส่วน!


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