DDD เป็นไปตาม OOP: วิธีการใช้พื้นที่เก็บข้อมูลเชิงวัตถุ?


12

การใช้งานทั่วไปของแหล่งเก็บข้อมูล DDD ดูไม่ OO มากเช่นsave()วิธีการ:

package com.example.domain;

public class Product {  /* public attributes for brevity */
    public String name;
    public Double price;
}

public interface ProductRepo {
    void save(Product product);
} 

ส่วนโครงสร้างพื้นฐาน:

package com.example.infrastructure;
// imports...

public class JdbcProductRepo implements ProductRepo {
    private JdbcTemplate = ...

    public void save(Product product) {
        JdbcTemplate.update("INSERT INTO product (name, price) VALUES (?, ?)", 
            product.name, product.price);
    }
} 

อินเทอร์เฟซดังกล่าวคาดว่าProductจะเป็นรูปแบบของโลหิตจางอย่างน้อยก็ด้วย getters

ในทางตรงกันข้าม OOP บอกว่าProductวัตถุควรรู้วิธีการบันทึกตัวเอง

package com.example.domain;

public class Product {
    private String name;
    private Double price;

    void save() {
        // save the product
        // ???
    }
}

สิ่งคือเมื่อProductรู้วิธีการบันทึกตัวเองก็หมายความว่ารหัสโครงสร้างไม่ได้แยกออกจากรหัสโดเมน

บางทีเราสามารถมอบหมายการบันทึกไปยังวัตถุอื่น:

package com.example.domain;

public class Product {
    private String name;
    private Double price;

    void save(Storage storage) {
        storage
            .with("name", this.name)
            .with("price", this.price)
            .save();
    }
}

public interface Storage {
    Storage with(String name, Object value);
    void save();
}

ส่วนโครงสร้างพื้นฐาน:

package com.example.infrastructure;
// imports...

public class JdbcProductRepo implements ProductRepo {        
    public void save(Product product) {
        product.save(new JdbcStorage());
    }
}

class JdbcStorage implements Storage {
    private final JdbcTemplate = ...
    private final Map<String, Object> attrs = new HashMap<>();

    private final String tableName;

    public JdbcStorage(String tableName) {
        this.tableName = tableName;
    }

    public Storage with(String name, Object value) {
        attrs.put(name, value);
    }
    public void save() {
        JdbcTemplate.update("INSERT INTO " + tableName + " (name, price) VALUES (?, ?)", 
            attrs.get("name"), attrs.get("price"));
    }
}

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


6
OOP บอกว่าวัตถุผลิตภัณฑ์ควรรู้วิธีการช่วยตัวเอง - ฉันไม่แน่ใจว่าถูกต้องจริง ๆ ... OOP ในตัวมันเองไม่ได้บอกว่ามันเป็นปัญหาการออกแบบ / รูปแบบมากกว่า (ซึ่งเป็นที่ที่ DDD / อะไรก็ตามที่คุณ
-use เข้า

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

1
"สิ่งนี้ไม่ได้หมายความว่าวัตถุอื่นไม่สามารถรับผิดชอบต่อการคงอยู่ของรัฐได้" - ฉันไม่ได้พูดอย่างนั้น คำสั่งที่สำคัญคือวัตถุควรจะใช้งานได้ มันหมายความว่าวัตถุ (และไม่มีใคร) สามารถมอบหมายการดำเนินการนี้ให้กับวัตถุอื่น แต่ไม่ใช่วิธีอื่น ๆ : ไม่มีวัตถุใดที่ควรรวบรวมข้อมูลจากวัตถุแบบพาสซีฟเพื่อประมวลผลการดำเนินงานที่เห็นแก่ตัวของตัวเอง . ฉันพยายามใช้วิธีนี้ในตัวอย่างด้านบน
ttulka

1
@ jleach คุณพูดถูกแล้วการแยก OOP ของเรานั้นแตกต่างออกไปสำหรับฉัน getters + setters ไม่มี OOP เลยมิฉะนั้นคำถามของฉันก็ไม่มีเหตุผล ขอบคุณอยู่ดี! :-)
ttulka

1
นี่คือบทความเกี่ยวกับประเด็นของฉัน: martinfowler.com/bliki/AnemicDomainModel.htmlฉันไม่เห็นด้วยกับรูปแบบของโลหิตจางในทุกกรณีตัวอย่างเช่นมันเป็นกลยุทธ์ที่ดีสำหรับการเขียนโปรแกรมการทำงาน ไม่ใช่แค่ OOP
ttulka

คำตอบ:


7

คุณเขียน

ในทางกลับกัน OOP บอกว่าวัตถุผลิตภัณฑ์ควรรู้วิธีการบันทึกเอง

และในความคิดเห็น

... ควรรับผิดชอบการดำเนินการทั้งหมดที่เกิดขึ้น

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

ดังนั้นสิ่งที่อาจเป็นการดำเนินการโดเมนที่เหมาะสมสำหรับProduct? สิ่งนี้ขึ้นอยู่กับบริบทโดเมนของระบบแอปพลิเคชัน หากระบบมีขนาดเล็กและสนับสนุนการทำงานของ CRUD เพียงอย่างเดียวแน่นอน a Productอาจอยู่ในสถานะ "โลหิตจาง" ตามตัวอย่างของคุณ สำหรับแอพพลิเคชั่นประเภทนี้อาจเป็นที่ถกเถียงกันได้หากใส่การดำเนินการฐานข้อมูลลงในคลาส repo แยกต่างหากหรือใช้ DDD เลยก็คุ้มค่ากับความยุ่งยาก

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

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


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

"แต่นี่ยังหมายความว่าฉันต้องให้การเข้าถึงโครงสร้างภายในของวัตถุผ่านทะเยอทะยานและผู้ตั้งค่า" - ไม่น่าเป็นไปได้ สถานะภายในของวัตถุโดเมน persisting-ไม่รู้ก็มักจะได้รับโดยเฉพาะชุดของคุณลักษณะที่เกี่ยวข้องกับโดเมน สำหรับแอ็ตทริบิวต์เหล่านี้ต้องมี getters และ setters (หรือ constructor-initialization) มิฉะนั้นจะไม่มีการดำเนินการโดเมน "น่าสนใจ" ในหลาย ๆ เฟรมเวิร์กยังมีคุณสมบัติการคงอยู่ซึ่งอนุญาตให้คงคุณลักษณะส่วนบุคคลไว้โดยการสะท้อนดังนั้นการห่อหุ้มจึงใช้งานไม่ได้เฉพาะกับกลไกนี้เท่านั้นไม่ใช่สำหรับ "รหัสอื่น"
Doc Brown

1
ฉันยอมรับว่าการคงอยู่ไม่ได้เป็นส่วนหนึ่งของการดำเนินการกับโดเมนอย่างไรก็ตามควรเป็นส่วนหนึ่งของการดำเนินงานโดเมน "ของจริง" ภายในวัตถุที่ต้องการ ตัวอย่างเช่นAccount.transfer(amount)ควรคงอยู่การถ่ายโอน วิธีนี้เป็นความรับผิดชอบของวัตถุไม่ใช่ของนิติบุคคลภายนอก แสดงวัตถุบนมืออื่น ๆ ที่เป็นมักจะดำเนินงานโดเมน! ความต้องการมักจะอธิบายอย่างละเอียดถึงสิ่งที่ควรดู มันเป็นส่วนหนึ่งของภาษาในหมู่สมาชิกโครงการธุรกิจหรืออื่น ๆ
Robert Bräutigam

@ RobertBräutigam: คลาสสิกAccount.transferสำหรับมักจะเกี่ยวข้องกับวัตถุบัญชีสองและหน่วยงานวัตถุ การดำเนินการคงอยู่ของทรานแซคชันอาจเป็นส่วนหนึ่งของหลัง (เมื่อมีการเรียกไปยัง repos ที่เกี่ยวข้อง) ดังนั้นจึงยังคงอยู่นอกวิธี "โอนย้าย" ด้วยวิธีนี้Accountสามารถคงอยู่อย่างไม่รู้เขิน ฉันไม่ได้พูดแบบนี้ดีกว่าวิธีแก้ปัญหาที่คุณคาดไว้ แต่คุณก็เป็นหนึ่งในหลาย ๆ วิธีที่เป็นไปได้
Doc Brown

1
@ RobertBräutigamค่อนข้างแน่ใจว่าคุณคิดมากเกี่ยวกับความสัมพันธ์ระหว่างวัตถุกับตาราง คิดว่าวัตถุนั้นมีสถานะเป็นของตัวเองทั้งหมดอยู่ในความทรงจำ หลังจากทำการถ่ายโอนในวัตถุบัญชีของคุณคุณจะถูกทิ้งให้อยู่กับวัตถุที่มีสถานะใหม่ นั่นคือสิ่งที่คุณต้องการสานต่อและโชคดีที่วัตถุบัญชีมีวิธีแจ้งให้คุณทราบเกี่ยวกับสถานะของพวกเขา นั่นไม่ได้หมายความว่ารัฐของพวกเขาจะต้องเท่ากับตารางในฐานข้อมูล - นั่นคือจำนวนเงินที่โอนอาจเป็นวัตถุเงินที่มีจำนวนเงินดิบและสกุลเงิน
Steve Chamaillard

5

ทฤษฎีสำคัญกว่าการฝึกฝน

ประสบการณ์สอนเราว่า Product.Save () นำไปสู่ปัญหามากมาย เพื่อแก้ไขปัญหาเหล่านั้นเราได้คิดค้นรูปแบบพื้นที่เก็บข้อมูล

แน่นอนว่ามันเป็นการละเมิดกฎของ OOP ในการซ่อนข้อมูลผลิตภัณฑ์ แต่มันใช้งานได้ดี

มันยากมากที่จะสร้างกฎที่สอดคล้องกันซึ่งครอบคลุมทุกอย่างมากกว่าที่จะสร้างกฎที่ดีโดยทั่วไปที่มีข้อยกเว้น


3

DDD เป็นไปตาม OOP

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

ในทางตรงกันข้าม OOP บอกว่าวัตถุสินค้าควรรู้วิธีการบันทึกตัวเอง

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

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

พื้นฐานการเขียนเฉพาะฐานข้อมูลนั้นไม่มีประโยชน์อย่างยิ่งและในหน่วยความจำเทียบเท่าจะไม่มีประโยชน์มากกว่าการเรียงลำดับ "คงอยู่" ไม่มีจุดใดที่จะนำข้อมูลไปไว้ในProductวัตถุถ้าคุณจะไม่นำข้อมูลนั้นออกไป คุณไม่จำเป็นต้องใช้ "getters" - คุณไม่ได้พยายามแบ่งปันโครงสร้างข้อมูลผลิตภัณฑ์และแน่นอนว่าคุณไม่ควรแชร์การเข้าถึงที่ไม่แน่นอนกับการเป็นตัวแทนภายในของผลิตภัณฑ์

บางทีเราสามารถมอบหมายการบันทึกไปยังวัตถุอื่น:

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

interface ProductStorage {
    onProduct(String name, double price);
}

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

วิธีการนี้ - ผ่านข้อมูลผ่านการเรียกกลับมีบทบาทสำคัญในการพัฒนาของmocks ใน TDD

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

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

ฉันเข้าใจ DDD ว่าเป็นเทคนิค OOP และฉันต้องการเข้าใจอย่างถ่องแท้ว่าดูเหมือนขัดแย้ง

สิ่งหนึ่งที่ต้องจำไว้ - สมุดสีฟ้าเขียนเมื่อสิบห้าปีก่อนเมื่อ Java 1.4 ท่องไปทั่วโลก โดยเฉพาะอย่างยิ่งหนังสือเล่มนี้นำเสนอ Java generics - เรามีเทคนิคมากมายให้เราตอนนี้เมื่อ Evans พัฒนาความคิดของเขา


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

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

1
"วิธีการนี้ตรงกันข้ามกับสิ่งที่อีแวนส์อธิบายไว้ในสมุดสีฟ้า" - ดังนั้นจึงมีความตึงเครียดหลังจาก :-) ทั้งหมดนั่นคือประเด็นของคำถามของฉันฉันเข้าใจ DDD เป็นเทคนิค OOP และฉันต้องการ เข้าใจอย่างถ่องแท้ว่าดูเหมือนขัดแย้ง
ttulka

1
จากประสบการณ์ของฉันสิ่งต่าง ๆ เหล่านี้ (โดยทั่วไปแล้ว OOP, DDD, TDD, ตัวย่อของคุณ) เสียงดีและดีในตัวเอง แต่เมื่อใดก็ตามที่มีการใช้งาน "โลกแห่งความเป็นจริง" จะมีการแลกเปลี่ยนหรือ ความเพ้อฝันน้อยกว่าที่จะต้องทำให้มันใช้งานได้
jleach

ฉันไม่เห็นด้วยกับความคิดที่ว่าการคงอยู่ (และการนำเสนอ) เป็น "พิเศษ" อย่างใด พวกเขาจะไม่. พวกเขาควรเป็นส่วนหนึ่งของแบบจำลองเพื่อขยายความต้องการ ไม่จำเป็นต้องเป็นขอบเขตข้อมูล (ตามฐานข้อมูล) ภายในแอปพลิเคชันเว้นแต่จะมีข้อกำหนดตามจริงที่ตรงกันข้าม
Robert Bräutigam

1

ข้อสังเกตที่ดีมากฉันเห็นด้วยกับพวกคุณ นี่คือการพูดคุยของการเหมืองแร่ (แก้ไข: ภาพนิ่งเท่านั้น) ที่ว่าเรื่องนี้เชิงวัตถุ Domain ขับเคลื่อนการออกแบบ

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

Storageตัวอย่างอินเทอร์เฟซของคุณยอดเยี่ยมสมมติว่ากรอบStorageนั้นถือว่าเป็นกรอบภายนอกแม้ว่าคุณจะเขียน

นอกจากนี้save()ในวัตถุควรได้รับอนุญาตหากเป็นส่วนหนึ่งของโดเมน ("ภาษา") ตัวอย่างเช่นฉันไม่ควรจะต้องชัดเจน "บันทึกว่า" หลังจากที่ฉันโทรAccount transfer(amount)ฉันควรคาดหวังอย่างถูกต้องว่าหน้าที่ทางธุรกิจtransfer()จะยังคงมีอยู่ต่อไป

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


คุณคุยกับคนอื่นเพื่อดูบ้างไหม? (ฉันเห็นเป็นเพียงสไลด์ใต้ลิงก์) ขอบคุณ!
ttulka

ฉันมีบันทึกการพูดภาษาเยอรมันเท่านั้นที่นี่: javadevguy.wordpress.com/2018/11/26/ …
Robert Bräutigam

เยี่ยมมาก! (โชคดีที่ฉันพูดภาษาเยอรมันได้) ฉันคิดว่าบล็อกทั้งหมดของคุณน่าอ่าน ... ขอบคุณสำหรับการทำงานของคุณ!
ttulka

ตัวเลื่อนที่ชาญฉลาดมาก Robert ฉันพบว่ามันเป็นตัวอย่างที่ดี แต่ฉันก็รู้สึกว่าในตอนท้ายการแก้ปัญหาจำนวนมากที่ไม่ทำลาย encapsulation และ LoD ขึ้นอยู่กับการให้ความรับผิดชอบจำนวนมากกับวัตถุโดเมน: การพิมพ์การทำให้เป็นอนุกรมการจัดรูปแบบ UI และอื่น ๆ ไม่เพิ่มการเชื่อมต่อระหว่างโดเมนและทางเทคนิค (รายละเอียดการใช้งาน) ตัวอย่างเช่น AccountNumber ควบคู่กับ Apache Wicket API หรือบัญชีที่มีวัตถุ Json อะไร คุณคิดว่ามันคุ้มค่าหรือไม่
Laiv

@Laiv ไวยากรณ์ของคำถามของคุณแสดงให้เห็นว่ามีบางอย่างผิดปกติกับการใช้เทคโนโลยีในการใช้ฟังก์ชั่นทางธุรกิจหรือไม่? ลองคิดแบบนี้: มันไม่ใช่การมีเพศสัมพันธ์ระหว่างโดเมนกับเทคโนโลยีที่เป็นปัญหา แต่มันคือการเชื่อมต่อระหว่างระดับนามธรรมที่แตกต่างกัน ยกตัวอย่างเช่นAccountNumber ควรจะTextFieldรู้ว่ามันสามารถแสดงเป็น หากคนอื่น ๆ (เช่น "ดู") จะรู้สิ่งนี้นั่นคือการมีเพศสัมพันธ์ที่ไม่ควรมีอยู่เพราะองค์ประกอบนั้นจะต้องรู้ว่าสิ่งใดAccountNumberประกอบไปด้วยเช่นภายใน
Robert Bräutigam

1

บางทีเราสามารถมอบหมายการบันทึกไปยังวัตถุอื่น

หลีกเลี่ยงการแพร่กระจายความรู้ในด้านต่างๆโดยไม่จำเป็น ยิ่งรู้สิ่งต่าง ๆ เกี่ยวกับฟิลด์แต่ละฟิลด์ยิ่งยากที่จะเพิ่มหรือลบฟิลด์:

public class Product {
    private String name;
    private Double price;

    void save(Storage storage) {
        storage.save( toString() );
    }
}

นี่คือผลิตภัณฑ์ที่ไม่ทราบว่าคุณกำลังบันทึกลงในไฟล์บันทึกหรือฐานข้อมูลหรือทั้งสองอย่าง ที่นี่วิธีการบันทึกไม่มีความคิดถ้าคุณมี 4 หรือ 40 สาขา นั่นคือการรวมกันอย่างหลวม ๆ นั่นเป็นสิ่งที่ดี

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

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


นี่คือรหัสที่ฉันโพสต์ในคำถามใช่ไหม? ผมใช้MapคุณเสนอหรือString Listแต่ตามที่ @VoiceOfUnreason พูดถึงในคำตอบของเขาการแต่งงานยังคงอยู่ที่นั่นไม่ชัดเจน ยังไม่จำเป็นที่จะต้องทราบโครงสร้างข้อมูลของผลิตภัณฑ์เพื่อบันทึกทั้งในฐานข้อมูลหรือไฟล์บันทึกอย่างน้อยที่สุดเมื่ออ่านกลับเป็นวัตถุ
ttulka

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


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

นั่นเป็นความเข้าใจผิด คอมไพเลอร์ไม่สามารถตรวจสอบล็อกไฟล์หรือฐานข้อมูล การตรวจสอบทั้งหมดคือถ้าไฟล์รหัสหนึ่งสอดคล้องกับไฟล์รหัสอื่นที่ไม่รับประกันว่าจะสอดคล้องกับไฟล์บันทึกหรือฐานข้อมูล
candied_orange

0

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้ฉันขอแนะนำหนังสือยอดเยี่ยม: "รูปแบบหลักการและแนวทางปฏิบัติของการออกแบบที่ขับเคลื่อนด้วยโดเมน" โดย Scott Millett และ Nick Tune

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