鍍金池/ 問答/Java  PHP  C++  網(wǎng)絡(luò)安全/ (PHP)單例模式 怎么蹦出好多問題, 煩請(qǐng)大家?guī)兔χ更c(diǎn)一二

(PHP)單例模式 怎么蹦出好多問題, 煩請(qǐng)大家?guī)兔χ更c(diǎn)一二

最近無意中看到一些對(duì)·單例模式·介紹的資料,有以下幾個(gè)疑問:

  1. 很多資料說單例模式無法繼承, 我自己覺得不對(duì), 單例模式完全可以將private設(shè)置為protected, 然后將self設(shè)置為static來實(shí)現(xiàn)繼承功能呀, 不知道說無法繼承的是哪個(gè)角度思考的, 所以有疑問?
  2. 假設(shè)我的項(xiàng)目中有很多功能, 我的理解是 "用戶每操作一下, 都會(huì)產(chǎn)生一個(gè)進(jìn)程, 或者是一個(gè)進(jìn)程中制作一次請(qǐng)求--相應(yīng)操作, 然后當(dāng)前操作在服務(wù)器運(yùn)行完成并返回響應(yīng), 則進(jìn)程結(jié)束, 這樣的話, 假設(shè)你有個(gè)單例類是Log類, 用來記錄日志, 那么本次進(jìn)程結(jié)束后, 進(jìn)程中的單例自然也就被銷毀了, 另外一次操作的話, 這次操作會(huì)再次生成新的Log實(shí)例"

    • 所以單例應(yīng)該是按一個(gè)個(gè)的進(jìn)程為單位來討論的, 但是很多資料說 "如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收,這將導(dǎo)致對(duì)象狀態(tài)的丟失。" 這怎么理解? 多長(zhǎng)時(shí)間算是長(zhǎng)?
    • 畢竟我的項(xiàng)目根據(jù)功能點(diǎn)的不同, 可能有些功能點(diǎn)復(fù)雜, 有些簡(jiǎn)單, 我的Log實(shí)例要在每個(gè)功能中做日志記錄, 難道還得考慮功能運(yùn)行過長(zhǎng)的話.... 我的日志會(huì)丟失一部分?
  3. 還有資料說:"濫用單例將帶來一些負(fù)面問題,如為了節(jié)省資源將數(shù)據(jù)庫連接池對(duì)象設(shè)計(jì)為的單例類,可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過多而出現(xiàn)連接池溢出"

    • 數(shù)據(jù)庫連接池一般不就是個(gè)類似數(shù)組的容器么? 我第一次建立好數(shù)據(jù)庫連接之后, 將連接對(duì)象放入連接池中, 如果進(jìn)程中再次需要連接數(shù)據(jù)庫的話, 直接從連接池中取出之前創(chuàng)建好的連接對(duì)象不就行了(而且我看比如TP3.2就是這么做的)
    • 所謂 "連接池溢出" 是什么意思, 難道是說本次進(jìn)程中有 n 個(gè) 不同的數(shù)據(jù)庫連接, 導(dǎo)致連接池中存放數(shù)據(jù)對(duì)象過大導(dǎo)致的內(nèi)存溢出?
    • 不應(yīng)該吧, 如果連接池是數(shù)組, 能放不少數(shù)據(jù)的啊, 而什么業(yè)務(wù)能在一個(gè)進(jìn)程中操作這么多不同的數(shù)據(jù)庫連接, 所以還是沒能理解
  4. TP3.2框架使用單例也是非完全套用 三私一公 來實(shí)現(xiàn)的, 比如ThinkDriverDb 只做到靜態(tài)化所有方法即可, 你即使new出來也沒用, 這樣是不是也沒什么槽點(diǎn)?
回答
編輯回答
風(fēng)畔

<?php

//final防止類被繼承
final class DBHelper{
    //初始化實(shí)例 含義:$install = new DBHelper()...
    private static $instance=null;
     
    //構(gòu)造器私有,防止類外部實(shí)例化
    private function __construct(){
        //連接數(shù)據(jù)庫操作
    }
     
    //獲取實(shí)例
    public static function getInstance(){
        if(!(self::$instance instanceof self)){
            self::$instance=new self;
        }
         
        return self::$instance;
    }
     
    //防止實(shí)例被克隆
    private function __clone(){
    }
     
}    
     
 

?>

參考:http://blog.51cto.com/phpme/2...

2017年10月17日 02:42
編輯回答
話寡

1.單例即類只有一個(gè)示例,如果繼承,那就會(huì)產(chǎn)生多個(gè)實(shí)例,此時(shí)已經(jīng)不是單例了。

2.理解差不多沒錯(cuò),單例解決的是同一個(gè)請(qǐng)求內(nèi),多處使用同一個(gè)類的問題。。比如一個(gè)請(qǐng)求內(nèi),可能要查十次數(shù)據(jù)庫,單例就是保證這十次使用的是同一個(gè)數(shù)據(jù)庫連接實(shí)例,而不是每次查詢都實(shí)例化一次。

3.濫用單例可能導(dǎo)致連接池溢出,這個(gè)問題應(yīng)該只存在于 java 中或類似得,猜測(cè):因?yàn)閖ava采用數(shù)據(jù)庫連接池技術(shù),因?yàn)閖ava是持久化服務(wù),濫用單例導(dǎo)致連接得不到釋放,內(nèi)存不斷上升導(dǎo)致溢出。而php這種請(qǐng)求結(jié)束,所有連接及內(nèi)存都會(huì)釋放,不存在這個(gè)問題。

4.所有的設(shè)計(jì)模式都是為了要實(shí)現(xiàn)功能而服務(wù),所以需要先看你想實(shí)現(xiàn)什么東西。靈活運(yùn)用各種模式,以及其變種,才能寫出更好的代碼。。。

所以不用執(zhí)著于你的四個(gè)問題是否有答案,知道有單例這個(gè)東西,知道多個(gè)示例與單個(gè)示例的區(qū)別,然后你的代碼需要優(yōu)化的時(shí)候,按照自己的需求來就行

2017年10月19日 03:09
編輯回答
過客

clipboard.png

  1. 我是覺得可以繼承的,使用static關(guān)鍵字

字太多,看得有點(diǎn)暈,你整理一下吧

2017年1月2日 02:23
編輯回答
晚風(fēng)眠

首先,我們來看一個(gè)完整的、規(guī)范的、簡(jiǎn)單的單例模式的例子:

<?php

class User {
    //靜態(tài)變量保存全局實(shí)例
    private static $_instance = null;
    //私有構(gòu)造函數(shù),防止外界實(shí)例化對(duì)象
    private function __construct() {
    }
    //私有克隆函數(shù),防止外辦克隆對(duì)象
    private function __clone() {
    }
    //靜態(tài)方法,單例統(tǒng)一訪問入口
    static public function getInstance() {
        if (is_null ( self::$_instance ) || !isset ( self::$_instance )) {
            self::$_instance = new self ();
        }
        return self::$_instance;
    }
    public function getName() {
        echo 'hello world!';
    }
}
$user = User::getInstance();
?>

下面回答問題:

1、你可以隨便改你所謂的單例模式類,但是單例的核心是不能變的:產(chǎn)出一個(gè)實(shí)例;每次使用同一個(gè)實(shí)例對(duì)象;;如果你把private改成protected可以,但是這就無限實(shí)例了不是嗎?不符合單例模式的設(shè)計(jì)規(guī)范呀;

2、這就是php的變量生命周期問題了。php所有的變量生命周期,一般情況下只存在于請(qǐng)求開始->請(qǐng)求結(jié)束,每次請(qǐng)求每個(gè)變量重新被賦值,每個(gè)對(duì)象被重新實(shí)例化;請(qǐng)求結(jié)束,自動(dòng)釋放;單例模式的的意義是:對(duì)象只被實(shí)例化一次,每次調(diào)用返回同一個(gè)實(shí)例;你的單例的生命周期只存在于這一請(qǐng)求過程中,請(qǐng)求結(jié)束,就沒了。再次請(qǐng)求,從新生成新的單例;沒毛病呀

3、濫用什么服務(wù)都會(huì)造成不好的影響;就你現(xiàn)在舉這個(gè)例子而言,對(duì)數(shù)據(jù)庫鏈接使用單例模式的話,每次使用的時(shí)候,都是用的同一靜態(tài)內(nèi)存區(qū)(類中static聲明的變量默認(rèn)保存在靜態(tài)內(nèi)存區(qū)中)的變量,所以只要實(shí)例化一次,之后在同一請(qǐng)求中使用的時(shí)候,就不會(huì)增加額外的數(shù)據(jù)庫連接對(duì)象了。

而你說的連接池指的是數(shù)據(jù)庫的連接池吧,這個(gè)連接池是有內(nèi)存限制,也有最大,最小連接限制,而且是可以在mysql的配置文件中設(shè)置的。具體請(qǐng)參考《MySql數(shù)據(jù)庫連接池專題》的介紹。

4、對(duì)TP的源碼沒看過,不方便回答。

以上。

2018年4月3日 10:51