2008-12-09 5 views
6

Tôi thường muốn kích hoạt một chức năng nhất định chỉ một lần, nhưng tôi cần phải kích hoạt nó từ bên trong một hàm khác được gọi lặp đi lặp lại. Ví dụ, chụp một cái gì đó để sử dụng sau này. Tôi thường làm điều đó bằng cách thiết lập một boolean toàn cầu.Làm thế nào để kích hoạt một chức năng một lần, và chỉ một lần ...?

Tôi tự hỏi liệu cách tôi thực hiện nó có thực sự là cách tốt nhất không?

Tôi dường như nhớ lại rằng các biến toàn cầu là xấu, và các biến boolean toàn cầu thậm chí còn tồi tệ hơn!

Dù sao, đây là cách tôi thường thực hiện kích hoạt một phương pháp nhất định chỉ một lần:

Trong thiết lập ban đầu của tôi về biến ...

private var myStatus:Boolean = false; 

Sau đó, trong phạm vi chức năng đó được gọi là thường .. .

if (!myStatus) { 
    doMyFunction(); 
    myStatus = true; 
} 

có vẻ như khá logic với tôi, nhưng nó điều đúng đắn?

CẬP NHẬT: Vâng, dựa trên những gì tôi đã học được từ câu trả lời của bạn, trước tiên hãy kiểm tra xem nút XML có tồn tại hay không. đĩa xảy ra), và, nếu không, sau đó tôi nối thêm một nút mới với dữ liệu ảnh được mã hóa base64. Tôi vẫn đặt cờ boolean để sau này tôi có thể ghi đè hình ảnh trống với dữ liệu hình ảnh đã chỉnh sửa của người dùng nếu cần. Nó hoạt động hoàn hảo. Cảm ơn mọi sự giúp đỡ của bạn!

Tôi cũng cảm thấy thoải mái hơn khi sử dụng hệ thống cụ thể (không an toàn) trong một số trường hợp nhất định.

Trả lời

7

Khi bạn gọi một hàm, nó sẽ làm những gì bạn mong đợi nó làm với các đối số bạn đưa ra. Nếu bạn gọi một hàm hai lần chính xác giống như cách bạn nên mong đợi hàm đó để cung cấp cho bạn cùng một kết quả hoặc làm điều tương tự.

Có lẽ tốt hơn là hãy chuyển sự phụ thuộc một lần này sang logic gọi hàm của bạn nhiều lần. Nếu bạn chỉ cần gọi hàm một lần thì chỉ cần gọi nó một lần. Ngoài ra, chuyển các đối số khác nhau cho hàm để chỉ ra rằng bạn đang làm điều gì đó khác.

+0

Nhưng nếu hàm trả về kết quả của một câu lệnh case, và bạn muốn một trong các câu lệnh case để có thể chạy một hàm chỉ lần đầu tiên nó được trả lại? Hay tôi vẫn chưa nhận được nó? – defmeta

+0

@defmeta: Tôi nghĩ anh ấy có nghĩa là xem xét lý do tại sao bạn chỉ chạy mã một lần. Nếu nó là để thiết lập, có thể bạn có thể đơn giản hóa bằng cách di chuyển các thiết lập ra một giai đoạn trước đó. Nếu bạn đang lưu vào bộ nhớ đệm một kết quả đắt tiền mà có thể không bao giờ cần thiết, thì chắc chắn, hãy tiếp tục và làm điều đó khi sử dụng lần đầu tiên. –

+0

@defmeta: onebyone là đúng - có thể bạn có thể cụ thể hơn một chút về chức năng chạy một lần của bạn cần làm gì? Có tác dụng phụ nào khi gọi chức năng này không? Điều gì xảy ra nếu bạn gọi nó hai lần? – rojoca

0

Tôi thấy không có gì sai với cách tiếp cận của bạn ở đây. Hãy nhớ rằng không phải lúc nào cũng có điều "Đúng" ... có những điều sai trái nhất định nhưng điều đúng là có thể chủ quan, và cũng có thể phụ thuộc đáng kể dựa trên các yêu cầu của hệ thống.

0

Tôi không thấy bất kỳ cách nào khác. Điều duy nhất mà nói đến cái tâm về làm thế nào để cải thiện điều này là - thread an toàn. Nhưng điều đó chỉ cần thiết nếu bạn có nhiều luồng gọi hàm.

5

Nó thực sự phụ thuộc vào chính xác những gì bạn muốn nói. Nếu mã của bạn sẽ được gọi từ nhiều hơn một luồng, thì bạn có một điều kiện chủng tộc có thể có nghĩa là doMyFunction có thể được gọi nhiều lần. Điều này là do nhiều hơn một chủ đề có thể kiểm tra myStatus, thấy rằng nó là sai, sau đó gọi doMyFunction. Bạn có thể cải thiện tình huống này một chút bằng cách đặt biến trước tiên:

if (!myStatus) { 
    myStatus = true; 
    doMyFunction(); 
} 

nhưng chỉ thu hẹp cửa sổ cho các sự cố, không loại trừ cửa sổ.

Để loại bỏ tình trạng cuộc đua, bạn cần khóa.

+0

Vâng, ví dụ cụ thể này nằm trong một ứng dụng Flex khá thiết kế procedurally, mặc dù các câu lệnh if nằm trong một tuyên bố trường hợp/switch mà hình dung có thể được gọi hai lần nếu có net nghiêm trọng tắc nghẽn. Tôi chắc chắn sẽ di chuyển biến setter lên. Cảm ơn! – defmeta

2

Chủ đề không an toàn. Điều đó có thể không quan trọng với bạn, nhưng bạn đã nói "ngôn ngữ bất khả tri": có thể bạn sẽ không muốn sử dụng mẫu này trong một thư viện đa năng cho Java.

Đây là câu hỏi khó trả lời theo cách không thuyết phục về ngôn ngữ, bởi vì các lựa chọn thay thế sẵn có phụ thuộc rất nhiều vào ngôn ngữ. Ví dụ trên POSIX bạn đã có pthread_once nếu bạn cần an toàn luồng.Trong C, bạn đã có các biến cục bộ tĩnh để lấy boolean đó ra khỏi phạm vi toàn cục. Trong bất kỳ ngôn ngữ OO nào, nếu bạn đang chụp ảnh "cái gì đó" để sử dụng sau này, thì có thể có một đối tượng phù hợp tương ứng với "cái gì đó" (hoặc ảnh chụp nhanh), có thể lưu trữ cờ.

4

Trong C/C++ bạn thường có thể giữ cho thực tế là doMyFunction() được gọi chỉ một lần đóng gói bằng cách sử dụng một biến tĩnh như vậy:

void doMyFunction() { 
    // gets called only once. 
    // side effects go here. 
} 

void functionThatGetsCalledALot() { 
    static bool called = false; 
    if (!called) { 
     doMyFunction(); 
     called = true; 
    } 
    // do more stuff 
} 

Điều này tránh việc sử dụng các globals nhưng có tác dụng tương tự, và var tĩnh được khai báo đúng nơi nó có liên quan, vì vậy nó rõ ràng những gì đang xảy ra. Lưu ý rằng đây không phải là chủ đề an toàn, vì vậy bạn sẽ cần một khóa nếu bạn có chủ đề.

+0

Điều này là sai tôi nghĩ. Bạn cần phải khai báo "được gọi" bên ngoài hàmThatGetsCalledALot, nếu không hàm doMyFunction sẽ được gọi là mọi lúc và không phải một lần. – GeneCode

+0

Không, đúng vậy. Cả hai đều làm việc, nhưng sử dụng một biến cục bộ tĩnh là sạch hơn vì bạn không gây ô nhiễm không gian tên chung. Bạn đã thực sự cố gắng chạy nó? Tra cứu các biến cục bộ tĩnh: http://en.wikipedia.org/wiki/Local_variable#Static_local_variables – tgamblin

0

Trong Perl 5.10 trở lên, bạn sẽ sử dụng biến số state.

use 5.010; 

sub test{ 
    state $once = 1; 

    if($once){ 
    $once = undef; 
    say 'first'; 
    } else { 
    say 'not first'; 
    } 
} 

test for 1..5; 

đầu ra

 
first 
not first 
not first 
not first 
not first