อินเตอร์เฟซแยกต่างหากสำหรับวิธีการกลายพันธุ์


11

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

ฉันมีอินเตอร์เฟซที่Fooกำหนดเป็น

public interface Foo {

    int getX();

    int getY();

    int getZ();
}

และการดำเนินการตาม

public final class DefaultFoo implements Foo {

    public DefaultFoo(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getZ() {
        return z;
    }

    private final int x;
    private final int y;
    private final int z;
}

ฉันยังมีอินเทอร์เฟซMutableFooที่ให้การเปลี่ยนแปลงที่ตรงกัน

/**
 * This class extends Foo, because a 'write-only' instance should not
 * be possible and a bit counter-intuitive.
 */
public interface MutableFoo extends Foo {

    void setX(int newX);

    void setY(int newY);

    void setZ(int newZ);
}

มีการใช้งานสองสามอย่างMutableFooที่อาจมีอยู่ (ฉันยังไม่ได้ใช้งาน) หนึ่งในนั้นคือ

public final class DefaultMutableFoo implements MutableFoo {

    /**
     * A DefaultMutableFoo is not conceptually constructed 
     * without all values being set.
     */
    public DefaultMutableFoo(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return x;
    }

    public void setX(int newX) {
        this.x = newX;
    }

    public int getY() {
        return y;
    }

    public void setY(int newY) {
        this.y = newY;
    }

    public int getZ() {
        return z;
    }

    public void setZ(int newZ) {
        this.z = newZ;
    }

    private int x;
    private int y;
    private int z;
}

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

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

/**
 * The EffectiveStats can never be modified independently of either the baseStats
 * or trained stats. As such, this StatSet must never provide mutators.
 */
public StatSet calculateEffectiveStats() {
    int effectiveHitpoints =
        baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
    int effectiveAttack = 
        baseStats.getAttack() + (trainedStats.getAttack() / 4);
    int effectiveDefense = 
        baseStats.getDefense() + (trainedStats.getDefense() / 4);

    return StatSetFactory.createImmutableStatSet(effectiveHitpoints, effectiveAttack, effectiveDefense);
}

ระยะเวลาที่ได้รับการฝึกฝนจะเพิ่มขึ้นหลังจากการต่อสู้ทุกครั้ง

public void grantExperience() {
    int hitpointsReward = 0;
    int attackReward = 0;
    int defenseReward = 0;

    final StatSet enemyStats = enemy.getEffectiveStats();
    final StatSet currentStats = player.getEffectiveStats();
    if (enemyStats.getHitpoints() >= currentStats.getHitpoints()) {
        hitpointsReward++;
    }
    if (enemyStats.getAttack() >= currentStats.getAttack()) {
        attackReward++;
    }
    if (enemyStats.getDefense() >= currentStats.getDefense()) {
        defenseReward++;
    }

    final MutableStatSet trainedStats = player.getTrainedStats();
    trainedStats.increaseHitpoints(hitpointsReward);
    trainedStats.increaseAttack(attackReward);
    trainedStats.increaseDefense(defenseReward);
}

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

ตอนนี้สำหรับคำถามของฉัน:

  1. มีชื่อสำหรับการแยกส่วนติดต่อโดย accessors และ mutators เป็นส่วนต่อประสานที่แยกกันหรือไม่?
  2. การแยกพวกเขาด้วยวิธีนี้ 'ถูกต้อง' หากพวกเขามีแนวโน้มที่จะใช้เท่ากันหรือมีรูปแบบที่แตกต่างและเป็นที่ยอมรับมากกว่าที่ฉันควรใช้แทน (เช่นFoo foo = FooFactory.createImmutableFoo();ซึ่งสามารถกลับมาได้DefaultFooหรือDefaultMutableFooซ่อนอยู่เพราะcreateImmutableFooกลับFoo)
  3. มีข้อเสียที่มองเห็นได้ในทันทีที่ใช้รูปแบบนี้บันทึกเพื่อทำให้ลำดับชั้นของอินเทอร์เฟซซับซ้อนหรือไม่

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

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

public class EffectiveStatSet implements StatSet {

    public EffectiveStatSet(StatSet baseStats, StatSet trainedStats) {
        // ...
    }

    public int getHitpoints() {
        return baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
    }
}


1
ฉันคิดว่าปัญหาคือวัตถุของคุณไม่แน่นอนแม้ว่าคุณจะเข้าถึงส่วนต่อประสานที่ไม่เปลี่ยนแปลง ดีกว่าที่จะมีวัตถุที่ไม่แน่นอนกับ Player.TrainStats ()
Ewan

@gnat คุณมีการอ้างอิงถึงที่ฉันสามารถเรียนรู้เพิ่มเติมเกี่ยวกับที่? จากคำถามที่แก้ไขแล้วฉันไม่แน่ใจว่าจะนำไปใช้ได้อย่างไร
Zymus

@gnat: ลิงก์ของคุณ (และลิงก์ระดับที่สองและสามองศา) นั้นมีประโยชน์มาก แต่วลีที่จับต้องได้ของปัญญานั้นมีประโยชน์เล็กน้อย มันดึงดูดความเข้าใจผิดและดูถูกเท่านั้น
ร. ว.

คำตอบ:


6

สำหรับฉันดูเหมือนว่าคุณมีทางออกสำหรับปัญหา

มีชื่อสำหรับการแยกส่วนติดต่อโดย accessors และ mutators เป็นส่วนต่อประสานที่แยกกันหรือไม่?

นี่อาจจะเป็นการยั่วยุเล็กน้อย แต่จริงๆแล้วฉันจะเรียกมันว่า "การออกแบบสิ่งต่าง ๆ มากเกินไป" หรือ "สิ่งที่ซับซ้อนเกินไป" ด้วยการเสนอตัวแปรที่ไม่แน่นอนและตัวแปรที่ไม่เปลี่ยนแปลงของคลาสเดียวกันคุณนำเสนอโซลูชันที่เทียบเท่ากับการใช้งานได้สองวิธีสำหรับปัญหาเดียวกันซึ่งแตกต่างกันเฉพาะในด้านที่ไม่สามารถใช้งานได้เช่นพฤติกรรมประสิทธิภาพ API และความปลอดภัยจากผลข้างเคียง ฉันเดาว่าเป็นเพราะคุณกลัวที่จะตัดสินใจเลือกสิ่งที่ต้องการหรือเพราะคุณพยายามใช้คุณสมบัติ "const" ของ C ++ ใน C # ฉันเดาใน 99% ของทุกกรณีมันจะไม่สร้างความแตกต่างใหญ่ถ้าผู้ใช้เลือกตัวแปรที่ไม่แน่นอนหรือตัวแปรที่ไม่เปลี่ยนรูปเขาสามารถแก้ปัญหาของเขากับสิ่งใดสิ่งหนึ่งหรืออื่น ๆ ดังนั้น "ความน่าจะเป็นของชั้นเรียนที่จะใช้"

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

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

"รูปแบบที่ยอมรับมากขึ้น" เรียกว่า KISS - ทำให้มันง่ายและโง่ ตัดสินใจหรือต่อต้านความไม่แน่นอนสำหรับคลาส / อินเตอร์เฟสเฉพาะในไลบรารีของคุณ ตัวอย่างเช่นหาก "StatSet" ของคุณมีแอตทริบิวต์มากกว่าหนึ่งโหลขึ้นไปและส่วนใหญ่จะถูกเปลี่ยนเป็นรายบุคคลฉันจะชอบชุดตัวเลือกที่ผันแปรได้และไม่ปรับเปลี่ยนฐานสถิติที่ไม่ควรแก้ไข สำหรับบางอย่างเช่นFooคลาสที่มีคุณลักษณะ X, Y, Z (เวกเตอร์สามมิติ) ฉันอาจชอบตัวแปรที่ไม่เปลี่ยนรูป

มีข้อเสียที่มองเห็นได้ในทันทีที่ใช้รูปแบบนี้บันทึกเพื่อทำให้ลำดับชั้นของอินเทอร์เฟซซับซ้อนหรือไม่

การออกแบบที่ซับซ้อนทำให้ซอฟต์แวร์ยากต่อการทดสอบยากที่จะรักษาและยากที่จะพัฒนา


1
ฉันคิดว่าคุณหมายถึง "KISS - ทำให้ง่ายโง่"
Epicblood

2

มีชื่อสำหรับการแยกส่วนติดต่อโดย accessors และ mutators เป็นส่วนต่อประสานที่แยกกันหรือไม่?

อาจจะมีชื่อนี้ถ้าแยกนี้จะเป็นประโยชน์และให้ผลประโยชน์ซึ่งผมเห็น Donot หากกองทหารไม่ได้ให้ประโยชน์อีกสองคำถามก็ไม่มีเหตุผล

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

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

การใช้งานที่ฉันได้เห็นไม่ได้แยกอินเทอร์เฟซ

  • ไม่มีอินเตอร์เฟส ReadOnlyList ใน java

รุ่น ReadOnly ใช้ "WritableInterface" และส่งข้อยกเว้นถ้าวิธีการเขียนถูก uesed


ฉันแก้ไข OP เพื่ออธิบายกรณีการใช้งานหลัก
Zymus

2
"ไม่มีส่วนติดต่อ ReadOnly ใน java" - ตรงไปตรงมาควรมี หากคุณมีรหัสส่วนหนึ่งที่ยอมรับ List <T> เป็นพารามิเตอร์คุณจะไม่สามารถบอกได้อย่างง่ายดายว่ามันจะทำงานกับรายการที่ไม่สามารถแก้ไขได้หรือไม่ รหัสที่ส่งคืนรายการไม่มีทางรู้ว่าคุณสามารถปรับเปลี่ยนได้อย่างปลอดภัยหรือไม่ ตัวเลือกเดียวนั้นขึ้นอยู่กับเอกสารที่อาจไม่สมบูรณ์หรือไม่ถูกต้องหรือทำสำเนาเพื่อป้องกันในกรณีที่ ประเภทคอลเลกชันแบบอ่านอย่างเดียวจะทำให้ง่ายขึ้นมาก
จูลส์

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

1

การแยกอินเตอร์เฟสการรวบรวมที่ไม่แน่นอนและอินเตอร์เฟสการรวบรวมแบบสัญญาอย่างเดียวเป็นตัวอย่างของหลักการแยกอินเตอร์เฟส ฉันไม่คิดว่าจะมีชื่อพิเศษใด ๆ ที่มอบให้กับการประยุกต์ใช้หลักการแต่ละครั้ง

สังเกตคำไม่กี่คำที่นี่: "read-only-contract" และ "collection"

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

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

รูปแบบดังกล่าวมักพบเห็นได้ในวัตถุที่แสดงถึงการรวบรวมข้อมูล - รายการลำดับไฟล์ (สตรีม) เป็นต้น


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


นี่คือวิธีการของฉัน (ไม่ได้ขึ้นอยู่กับการเปลี่ยนแปลงไม่ได้)

  1. กำหนด DTO (วัตถุถ่ายโอนข้อมูล) หรือที่เรียกว่า tuple ค่า
    • DTO hitpointsนี้จะมีสามสาขา: attack, defense,
    • เพียงแค่ฟิลด์: สาธารณะทุกคนสามารถเขียนไม่มีการป้องกัน
    • อย่างไรก็ตาม DTO จะต้องเป็นวัตถุที่ถูกทิ้ง: ถ้าคลาสAต้องการส่ง DTO ไปยังคลาสBมันจะสร้างสำเนาของมันและส่งสำเนานั้นแทน ดังนั้นBสามารถใช้ DTO ได้อย่างไรก็ตามมันชอบ (เขียนถึงมัน) โดยไม่กระทบกับ DTO ที่Aยังคงอยู่
  2. grantExperienceฟังก์ชั่นที่จะถูกทำลายลงไปที่สอง:
    • calculateNewStats
    • increaseStats
  3. calculateNewStats จะรับอินพุตจาก DTO สองอันอันหนึ่งแสดงถึงสถิติผู้เล่นและอีกอันแสดงถึงสถิติศัตรูและทำการคำนวณ
    • สำหรับการป้อนข้อมูลผู้โทรควรเลือกระหว่างฐานการฝึกอบรมหรือสถิติที่มีประสิทธิภาพตามความต้องการของคุณ
    • ผลที่ตามมาจะเป็น DTO ใหม่ที่แต่ละเขต ( hitpoints, attack, defense) เก็บจำนวนที่จะเพิ่มขึ้นสำหรับความสามารถที่
    • DTO "จำนวนที่เพิ่มขึ้น" ใหม่ไม่เกี่ยวกับขีด จำกัด สูงสุด (กำหนดสูงสุดสูงสุด) สำหรับค่าเหล่านั้น
  4. increaseStats เป็นวิธีการของผู้เล่น (ไม่ใช่ใน DTO) ที่ใช้ "จำนวนที่เพิ่มขึ้น" DTO และใช้การเพิ่มนั้นใน DTO ที่เป็นของผู้เล่นและแสดงถึง DTO ที่ผู้เล่นสามารถฝึกได้ของผู้เล่น
    • หากมีค่าสูงสุดสำหรับสถิติเหล่านี้จะมีการบังคับใช้ที่นี่

ในกรณีที่calculateNewStatsพบว่าไม่ได้ขึ้นอยู่กับข้อมูลผู้เล่นหรือศัตรูอื่น ๆ (นอกเหนือจากค่าใน DTO สองอินพุต) วิธีนี้อาจอยู่ที่ใดก็ได้ในโครงการ

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


1

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

// Mutates mutableFoo
mutableFoo.setX(...)
// Creates a new updated immutableFoo, existing immutableFoo is unchanged
newFoo = immutableFoo.setX(...)

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

// Stats are mutable, mutates self.stats
self.stats.setX(...)

คุณมี:

// Stats are immutable, mutates self, setX() returns new updated stats
self.stats = self.stats.setX(...)

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

ซึ่งหมายความว่าวัตถุอื่น ๆ ในระบบของคุณไม่สามารถอ้างอิงการอ้างอิงไปยังวัตถุสถิติได้ - วัตถุสถิติที่พวกเขามีจะไม่เหมือนวัตถุสถิติที่ผู้เล่นมีหลังจากผู้เล่นอัปเดตสถิติของพวกเขา

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


1

ว้าว ... นี่นำฉันกลับมาจริงๆ ฉันลองความคิดเดียวกันนี้สองสามครั้ง ฉันดื้อเกินไปที่จะยอมแพ้เพราะฉันคิดว่าจะมีบางอย่างที่ดีในการเรียนรู้ ฉันเคยเห็นคนอื่นลองใช้รหัสนี้เช่นกัน การใช้งานส่วนใหญ่ที่ฉันเคยเห็นเรียกว่าอินเตอร์เฟสแบบอ่านอย่างเดียวเช่นคุณFooViewerหรือReadOnlyFooและส่วนติดต่อแบบเขียนอย่างเดียวFooEditorหรือWriteableFooหรือใน Java ฉันคิดว่าฉันเห็นFooMutatorครั้งเดียว ฉันไม่แน่ใจว่ามีคำศัพท์อย่างเป็นทางการหรือแม้แต่คำศัพท์ทั่วไปสำหรับการทำสิ่งนี้

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

ข้อเสียหนึ่งที่เป็นไปได้: การทำซ้ำ คุณจะต้องสร้างอินเทอร์เฟซเหล่านี้สำหรับคลาสจำนวนมากที่อาจเกิดขึ้นและแม้แต่คลาสเดียวคุณต้องตั้งชื่อแต่ละวิธีและอธิบายแต่ละลายเซ็นอย่างน้อยสองครั้ง ในทุกสิ่งที่ทำให้ฉันต้องเขียนโปรแกรมต้องเปลี่ยนไฟล์หลายไฟล์ด้วยวิธีนี้ทำให้ฉันประสบปัญหามากที่สุด ในที่สุดฉันก็ลืมที่จะเปลี่ยนแปลงในที่เดียวหรือที่อื่น เมื่อคุณมีคลาสที่ชื่อว่า Foo และส่วนต่อประสานที่เรียกว่า FooViewer และ FooEditor หากคุณตัดสินใจว่าจะดีกว่าถ้าคุณเรียกมันว่า Bar แทนคุณจะต้องปรับโครงสร้าง -> เปลี่ยนชื่อสามครั้งเว้นแต่คุณจะมี IDE ที่ฉลาดอย่างน่าอัศจรรย์ ฉันยังพบว่านี่เป็นกรณีเมื่อฉันมีรหัสจำนวนมากมาจากตัวสร้างรหัส

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

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

ฉันจะให้ความสำคัญกับองค์ประกอบที่คุณพูดถึงมากขึ้น ฉันอยากรู้ว่าทำไมคุณถึงรู้สึกว่ามันเป็นความคิดที่ไม่ดี ฉันคาดว่าจะมีการEffectiveStatsแต่งและไม่เปลี่ยนรูปStatsและสิ่งที่คล้าย ๆStatModifiersซึ่งจะเพิ่มเติมชุดของบางอย่างStatModifierที่เป็นตัวแทนของสิ่งที่อาจแก้ไขสถิติ (ผลกระทบชั่วคราวรายการที่ตั้งในพื้นที่การปรับปรุงบางส่วนความเหนื่อยล้า) แต่ที่คุณEffectiveStatsไม่จำเป็นต้องเข้าใจเพราะStatModifiersจะ จัดการสิ่งเหล่านั้นคืออะไรและมีผลกระทบมากน้อยแค่ไหนและพวกเขาจะมีสถิติแบบไหน StatModifierจะเป็นอินเทอร์เฟซสำหรับสิ่งต่าง ๆ และสามารถรู้สิ่งต่าง ๆ เช่น "ฉันอยู่ในโซน", "เมื่อยาเสื่อม" ฯลฯ ... แต่จะไม่ต้องให้วัตถุอื่นรู้สิ่งต่าง ๆ มันจะต้องบอกว่าสถิติและวิธีการแก้ไขมันตอนนี้ ยังดีกว่าStatModifierก็สามารถเปิดเผยวิธีการผลิตที่ไม่เปลี่ยนรูปใหม่Statsขึ้นอยู่กับอีกคนหนึ่งStatsซึ่งจะแตกต่างกันเพราะมันได้รับการแก้ไขอย่างเหมาะสม จากนั้นคุณสามารถทำสิ่งที่ชอบcurrentStats = statModifier2.modify(statModifier1.modify(baseStats))และทุกสิ่งStatsสามารถเปลี่ยนแปลงไม่ได้ baseStatsฉันจะไม่ได้รหัสที่โดยตรงผมอาจห่วงผ่านการปรับเปลี่ยนทั้งหมดและจะใช้แต่ละคนเพื่อผลของการปรับเปลี่ยนก่อนหน้านี้เริ่มต้นด้วย

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