"คงที่" เป็นเบาะแสความหมายเกี่ยวกับการไร้สัญชาติ?


11

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

ดังนั้นตอนนี้ที่ฉันใช้ Spring เพื่อสร้างวัตถุและโยงเข้าด้วยกันฉันจะกำจัดstaticคำหลักไปทางซ้ายและขวา (ถ้าฉันอาจต้องการเยาะเย้ยมันก็ไม่คงที่ในความหมายเดียวกับที่ Math.abs () ใช่ไหม?) สิ่งนี้คือฉันได้รับนิสัยการใช้staticเพื่อแสดงว่าวิธีการไม่ได้พึ่งพา ในสถานะวัตถุใด ๆ ตัวอย่างเช่น:

//Before
import com.thirdparty.ThirdPartyLibrary.Thingy;
public class ThirdPartyLibraryWrapper {
    public static Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
ThirdPartyLibraryWrapper.newThingy(input);
//After
public class ThirdPartyFactory {
    public Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
thirdPartyFactoryInstance.newThingy(input);

ดังนั้นนี่คือสถานที่ที่จะได้สัมผัสงอนงง ฉันชอบวิธีเดิมเพราะตัวพิมพ์ใหญ่บอกฉันว่าเหมือนกับ Math.sin (x) ThirdPartyLibraryWrapper.newThingy (x) ทำสิ่งเดียวกันทุกครั้ง ไม่มีสถานะของวัตถุที่จะเปลี่ยนวิธีที่วัตถุทำในสิ่งที่ฉันขอให้ทำ นี่คือคำตอบที่เป็นไปได้ที่ฉันกำลังพิจารณา

  • ไม่มีใครรู้สึกแบบนี้ดังนั้นจึงมีบางอย่างผิดปกติกับฉัน บางทีฉันอาจยังไม่ได้ทำให้วิธีการทำสิ่งต่าง ๆ เป็นจริง OO! บางทีฉันอาจจะเขียนเป็นภาษาจาวา แต่กำลังคิดในภาษา FORTRAN หรือบางอย่าง (ซึ่งน่าประทับใจเพราะฉันไม่เคยเขียน FORTRAN เลย)
  • บางทีฉันอาจใช้ staticness เป็นพร็อกซีสำหรับการเปลี่ยนแปลงไม่ได้เพื่อวัตถุประสงค์ในการให้เหตุผลเกี่ยวกับรหัส ที่ถูกกล่าวว่าฉันควรมีปม ในรหัสของฉันสำหรับคนที่มาพร้อมที่จะรักษามันให้รู้ว่ามีอะไร stateful และสิ่งที่ไม่?
  • บางทีนี่น่าจะมาฟรีถ้าฉันเลือกอุปมาอุปมัยที่ดี? เช่นthingyWrapperไม่มีเสียงเหมือนว่ามันมีรัฐอิสระของห่อThingyซึ่งตัวเองอาจจะไม่แน่นอน ในทำนองเดียวกันthingyFactoryเสียงเหมือนว่ามันควรจะไม่เปลี่ยนรูป แต่อาจมีกลยุทธ์ที่แตกต่างกันซึ่งได้รับการคัดเลือกในการสร้าง

คำตอบ:


12

ฉันชอบวิธีเดิมเพราะตัวพิมพ์ใหญ่บอกฉันว่าเหมือนกับ Math.sin (x) ThirdPartyLibraryWrapper.newThingy (x) ทำสิ่งเดียวกันทุกครั้ง ไม่มีสถานะของวัตถุที่จะเปลี่ยนวิธีที่วัตถุทำในสิ่งที่ฉันขอให้ทำ

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

พิจารณาสิ่งต่อไปนี้:

public static class Logger
{
    public static int LogLevel { get; set; }

    public static void Log(string message, int logLevel)
    {
        if (logLevel >= LogLevel)
        {
            // logs the message, but only if it is important enough.
        }
    }
}

คลาสนี้ไม่เพียงเก็บสถานะ แต่ลักษณะการทำงานของLogger.Log()วิธีการเปลี่ยนเมื่อสถานะนั้นเปลี่ยนไป มันเป็นแบบฝึกหัดที่ถูกต้องตามกฎหมายของstaticรูปแบบการเรียนที่ถูกต้องแต่ไม่มีการรับประกันความหมายใด ๆ ที่คุณแนะนำ


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

1
ปกติแล้วความคาดหวังดังกล่าวจะรวมอยู่ในเอกสารสำหรับวิธีการนั้น เช่นเดียวกับความปลอดภัยของเธรด
Robert Harvey

5

ในความคิดของฉันสิ่งที่คุณกำลังพูด - ฟังก์ชั่นคงที่ทั้งหมดจะเป็นโมฆะ - เป็นวิธีที่ดี OO ของการเขียนโค้ดในกรณีส่วนใหญ่ แต่ฉันไม่เชื่อว่าเมื่อคุณดูฟังก์ชั่นคงที่คุณควรถือว่าโดยอัตโนมัติว่าไม่มีผลข้างเคียง . สถานการณ์อาจซับซ้อนกว่านี้ ยกตัวอย่างฟังก์ชั่นClass.forName(String)ที่ดูเหมือนจะไร้สัญชาติ แต่จริงๆแล้วมันจะโหลดคลาสเข้าไปในหน่วยความจำและในที่สุดก็สร้างฟิลด์สแตติก / เรียกใช้ initializer คงที่ในที่สุด นี่เป็นตัวอย่างของฟังก์ชั่น idempotent (การเรียกในที่สุดหลังจากการโทรครั้งแรกสร้างความแตกต่าง) แต่มันไม่ใช่ฟังก์ชั่นที่บริสุทธิ์ (ไม่สามารถพูดได้ว่ามันไม่มีผลข้างเคียง) นี่เป็นตัวเลือกที่ดีเช่นกัน แต่อาจมีบางกรณีที่การเรียกฟังก์ชันที่แตกต่างกันสามครั้งให้ผลลัพธ์ที่แตกต่างกันสามอย่าง เช่นถ้าคุณโทรThread.currentThread() ในแอปพลิเคชันแบบมัลติเธรดไม่มีการรับประกันว่าคุณจะได้รับเธรดเดียวกันทุกครั้ง

ที่ถูกกล่าวว่าฉันควรมีปมในรหัสของฉันสำหรับคนที่มาพร้อมที่จะรักษามันให้รู้ว่ามีอะไร stateful และสิ่งที่ไม่?

ทางออกที่เหมาะสมคือจัดทำเอกสาร (Javadoc เป็นต้น); นอกจากนี้จากชื่อของฟังก์ชั่นและจากสิ่งที่มันทำบางครั้งก็สามารถอนุมานได้ว่าฟังก์ชั่นคงที่เป็นฟังก์ชั่นที่บริสุทธิ์ ตัวอย่างเช่นไม่มีเหตุผลที่ใครบางคนจะเชื่อว่าAssert.assertTrue(boolean)จาก JUnit จะเปลี่ยนสถานะบางแห่ง ในทางกลับกันเมื่อมีการSystem.clearProperty(String)เรียกใช้ฟังก์ชั่นคล้ายกันมันค่อนข้างชัดเจนว่าจะมีผลข้างเคียง


"nullipotent" และ "ไร้สัญชาติ" ต่างกันอย่างไร
Pacerier

@Pierier ไม่ควรมีความแตกต่าง
m3th0dman

4

ที่ถูกกล่าวว่าฉันควรมีปมในรหัสของฉันสำหรับคนที่มาพร้อมที่จะรักษามันให้รู้ว่ามีอะไร stateful และสิ่งที่ไม่?

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

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

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


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

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