เป็นการ“ เริ่มต้น”“ วิ่ง” หรือ“ ดำเนินการ” เป็นวิธีปฏิบัติที่ดีหรือไม่?


30

ฉันกำลังทำงานบนฐานรหัสที่มีหลายคลาสที่ใช้วิธีการเริ่มต้น ดูเหมือนว่าการก่อสร้างแบบสองเฟสสำหรับฉันซึ่งฉันถือว่าเป็นการปฏิบัติที่ไม่ดีอยู่เสมอ ฉันไม่สามารถบอกความแตกต่างระหว่างสิ่งนี้กับตัวสร้างได้

เมื่อใดจึงเหมาะสมที่จะใช้วิธีการเริ่มต้นแทนการสร้างวัตถุปกติ

เมื่อใดฉันจึงควรใช้ตัวสร้าง

แก้ไข: ฉันไม่คิดว่ามันเป็นสิ่งที่เกี่ยวข้อง แต่ภาษาการเขียนโปรแกรมคือ C # ซึ่งสามารถนำไปใช้กับ Java หรือ C ++ ได้อย่างเท่าเทียมกัน


3
คุณสามารถเพิ่มบริบทอีกเล็กน้อยได้หรือไม่ ภาษา? เธรดกับเธรดเดี่ยว? ความแตกต่างระหว่างstartและตัวสร้าง? ฯลฯ ...

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

2
@DaveHillier ตัวอย่างเช่นใน Perl มันเป็นมาตรฐานการปฏิบัติ (และหนึ่งที่ดี) จะมีinitวิธีการบางอย่างที่อยู่นอกการจัดเรียงของnewฟังก์ชั่น - perldoc.perl.org/perlobj.html สำนวนภาษาหนึ่งอาจทำงานได้ดีที่นั่นและไม่ใช่ในภาษาอื่น

1
ตัวอย่างของคลาสที่มีStartเมธอดใน API ทั่วไปรวมถึงเธรดและนาฬิกาจับเวลา
luiscubal

1
นับฉันในหมู่ผู้ที่ต้องการตัวอย่างโค้ดเพื่อทำความเข้าใจกับสิ่งที่คุณถามจริง ๆ
user16764

คำตอบ:


44

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

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

แน่นอนว่าStart()นี่เป็นวิธีที่มีประโยชน์ในวัตถุและไม่เทียบเท่ากับInitialize()วิธีการ หากเป็นเพียงวิธีพิเศษในการตั้งค่าพารามิเตอร์เพิ่มเติมไม่ควรมีอยู่


1
การใช้วิธีการเริ่มต้นก็คือเมื่อการดำเนินการเสร็จสิ้นจะสร้างเธรดผู้ปฏิบัติงานใหม่หรือตัวจับเวลา คอนสตรัคเตอร์ไม่ควรทำการยกของหนักเช่นนี้หรือสร้างผลข้างเคียงที่สำคัญ (เช่นการสร้างเธรดใหม่)
Ziv

50

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

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


16
การเปรียบเทียบที่ดี มันน่าสังเกตว่าStart()สามารถสอดคล้องกับสวิตช์เปิด / ปิด (เช่น lightswitch) ซึ่งควรมีStop()หรือกดปุ่ม (เช่นปุ่มพิมพ์บนเครื่องถ่ายเอกสาร) ซึ่งจะเปิดขึ้นและทำงานจนกว่าจะเสร็จสิ้น
Bobson

3
+1 พูดดีและยินดีต้อนรับสู่ P.SE คำตอบเช่นนี้เป็นการเริ่มต้นที่ดี
จิมมี่ฮอฟฟา

14

คุณอาจใช้การเริ่มต้นขี้เกียจ

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

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

ชะลอการเริ่มต้นที่มีราคาแพงจนกว่าจะจำเป็นครั้งแรก ..

ตัวอย่าง:

public class FooClass{

    private ExpensiveResource resource;
    private CheapResource cheap;

    public  FooClass(String someParameter){
        // constructor: initialize CheapResource cheap 
            // but NOT ExpensiveResource resource
    }

    public ExpensiveResource getExpensiveResource(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource
    }

    public String getExpensiveResourceName(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource.getName();
    }   

    public CheapResource getCheapResource(){
        return this.cheap;
    }

    private initializeExpensiveResource(){
        // do expensive initialization of field "resource"
    }

}

public class Test{
    public static void main (String args[]){

        FooClass foo = new FooClass("some string");
        CheapResource cr = foo.getCheapResource();
        String s = foo.getExpensiveResourceName(); 
          // just now is the expensive resource initialized

    }
}

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

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