设计模式之PHP项目应用——单例模式设计Memcache和Redis操作类

1 单例模式简介

    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

 

2 模式核心思想

    1)某个类只能有一个实例;
    2)它必须自行创建这个实例;

    3)它必须自行向整个系统提供这个实例。

 

3 模式架构图

 

4 项目应用

4.1 需求说明

    CleverCode在实际的PHP项目中,应用单例模式最多的就是涉及到网络连接的。比如Memcache和Redis连接,一般的需求通常Redis都只有一台服务器,所以用单例模式将连接封装到getInstance(),这样做的好处是不用每次都去调用connect()方法,减少网络连接开销。PHP都是单线程同步执行的,所以整个程序只用实例化一个Redis对象即可。(来之《CleverCode的项目》)

 

4.2 需求分析

    根据4.1可以分析出使用单例模式比较适合php网络连接的操作。如Mysql,Memcache,Redis,Gearman等都可以尝试单例模式。当然Mysql可能涉及到连接池,只需要将单例变成一个数组单例即可。即$_instance = null,变成$_instance = array(),$_instance['con1'] = new Self('conn1');$_instance['con2'] = new Self('conn2');

 

4.3 程序源码下载

http://download.csdn.net/detail/clevercode/8783989
 

4.4 程序说明



需要提前将Memcache与Redis加入到php扩展中。


1)单例模式设计Memcache操作类(MemcacheOperate.php)
<?php

/**
 * MemcacheOperate.php
 *
 * 单例模式设计Memcache操作类
 *
 * Copyright (c) 2015 http://blog.csdn.net/CleverCode
 *
 * modification history:
 * --------------------
 * 2015/6/8, by CleverCode, Create
 *
 */
class MemcacheOperate extends Memcache{
    
    // 实例
    protected static $_instance = null;

    /**
     * Singleton instance(获取自己的实例)
     *
     * @return MemcacheOperate
     */
    public static function getInstance(){
        if (null === self::$_instance) {
            
            self::$_instance = new self();
            $host = $_SERVER['MEMCACHE_HOST'];
            $port = $_SERVER['MEMCACHE_PORT'];
            self::$_instance->addServer($host, $port);
        }
        return self::$_instance;
    }
}





2)单例模式设计Redis操作类(RedisOperate.php)
<?php

/**
 * RedisOperate.php
 *
 * 单例模式设计Redis操作类
 *
 * Copyright (c) 2015 http://blog.csdn.net/CleverCode
 *
 * modification history:
 * --------------------
 * 2015/6/8, by CleverCode, Create
 *
 */
class RedisOperate extends Redis{
    
    // 实例
    protected static $_instance = null;

    /**
     * Singleton instance(获取自己的实例)
     *
     * @return RedisOperate
     */
    public static function getInstance(){
        if (null === self::$_instance) {
            
            self::$_instance = new self();
            $host = $_SERVER['REDIS_HOST'];
            $port = $_SERVER['REDIS_PORT'];
            self::$_instance->connect($host, $port);
        }
        return self::$_instance;
    }
}




3)客户端代码(singletonPattern.php)

 
<?php
/**
 * singletonPattern.php
 *
 * 单例模式
 * 
 * Copyright (c) 2015 http://blog.csdn.net/CleverCode
 *
 * modification history:
 * --------------------
 * 2015/6/8, by CleverCode, Create
 *
 */

// 加载Memcache
include_once ('MemcacheOperate.php');

// 加载Redis
include_once ('RedisOperate.php');

/*
 * 客户端类
 * 让客户端和业务逻辑尽可能的分离,降低客户端和业务逻辑算法的耦合,
 * 使业务逻辑的算法更具有可移植性
 */
class Client{

    /**
     * 初始化配置文件
     *
     * @return null
     */
    public static function initConfig(){
        // Memcache 主机
        $_SERVER['MEMCACHE_HOST'] = '192.168.6.201';
        
        // Memcache 端口
        $_SERVER['MEMCACHE_PORT'] = 11211;
        
        // Redis 主机
        $_SERVER['REDIS_HOST'] = '192.168.6.201';
        
        // Redis 端口
        $_SERVER['REDIS_PORT'] = 6379;
    }

    /**
     * 主函数
     *
     * @return null
     */
    public function main(){
        // 初始化配置
        self::initConfig();
        
        // Memcache key1
        MemcacheOperate::getInstance()->set('key1', 'Memcache CleverCode1', 0, 100);
        echo MemcacheOperate::getInstance()->get('key1');
        echo "\r\n---\r\n";
        
        // Memcache key2
        MemcacheOperate::getInstance()->set('key2', 'Memcache CleverCode2', 0, 100);
        echo MemcacheOperate::getInstance()->get('key2');
        echo "\r\n---\r\n";
        
        // Redis key3
        RedisOperate::getInstance()->set('key3', 'Redis CleverCode3');
        echo RedisOperate::getInstance()->get('key3');
        echo "\r\n---\r\n";
        
        // Redis key4
        RedisOperate::getInstance()->set('key4', 'Redis CleverCode4');
        echo RedisOperate::getInstance()->get('key4');
        echo "\r\n---\r\n";
    }
}

/**
 * 程序入口
 */
function start(){
    $client = new Client();
    $client->main();
}

start();

?>

4.5 程序运行结果展示

5 总结

5.1 优点



1)实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。


2)灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。

 

5.2 缺点



1)开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。


2)可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。


3)对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
 
 

 

技术交流

CleverCode是一名架构师,技术交流,咨询问题,请加CleverCode创建的qq群(架构师俱乐部):517133582。加群和腾讯,阿里,百度,新浪等公司的架构师交流。【架构师俱乐部】宗旨:帮助你成长为架构师!

 



 
 
<think>好的,用户想找LeetCode热门100题的C++解决方案。我需要先确定用户的具体需求,是不是需要具体的题目解答,比如算法思路、代码示例或者优化方法。用户提到的引用内容中有几个代码示例,比如二进制求、数组旋转、子数组能被K整除等,这些可能是top100中的题目。 首先,我应该整理LeetCode top100题中常见的题目类型,比如数组、字符串、动态规划、树、链表等。然后,根据用户提供的引用内容,看看是否有对应的题目可以举例。例如,引用1中的二进制求LeetCode第67题,属于字符串处理;引用2中的数组旋转是第189题,涉及数组操作;引用3子数组能被K整除是第974题,用到了前缀哈希表;引用4可能涉及图的最短路径问题,比如第743题。 接下来,我需要确保提供的代码示例符合用户要求,使用C++编写,并且是top100中的题目。可能需要确认每个引用对应的题目是否在top100列表中,但根据常见情况,像两数之、反转链表、二叉树遍历等都属于高频题。 用户可能需要每个题目的简要思路代码示例,同时生成相关问题。例如,对于快速排序,用户示例中提供了代码相关问题,这里需要类似的结构。需要注意的是,用户要求回答结构清晰,逐步解决问题,所以需要分步骤讲解每个题目的解决方法,并附上代码。 另外,引用内容中的代码需要注意格式是否正确,比如引用1中的二进制求代码是否有语法错误,是否需要调整。例如,代码中的循环条件字符串操作是否正确,是否有转义字符的问题。不过用户提供的代码可能存在一些HTML转义字符,比如<>,需要转换为<>,确保代码可读性。 最后,生成相关问题时要围绕每个题目的常见疑问,比如时间复杂度、优化方法、应用场景等。例如,对于数组旋转问题,可以问如何在不使用额外空间的情况下解决,或者如何优化反转方法的性能。 总结步骤: 1. 确定LeetCode top100中的常见题目,并匹配用户提供的引用中的例子。 2. 为每个例子提供问题描述、解决思路、代码示例,并确保代码正确。 3. 生成每个题目相关的后续问题,帮助用户深入理解。 4. 检查引用标记是否正确,代码格式是否符合要求,避免语法错误。 5. 使用中文回答,保持结构清晰,分点说明。</think>以下整理了LeetCode热门100题中部分经典问题的C++解决方案,涵盖关键思路与代码实现: --- ### 1. 两数之(Two Sum) **问题描述**:给定数组一个目标值,找出数组中两数之等于目标值的索引。 **解决思路**:利用哈希表记录遍历过的数值及其索引,实现$O(1)$时间复杂度的查找[^1]。 ```cpp #include <vector> #include <unordered_map> using namespace std; class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> num_map; for (int i = 0; i < nums.size(); ++i) { int complement = target - nums[i]; if (num_map.find(complement) != num_map.end()) { return {num_map[complement], i}; } num_map[nums[i]] = i; } return {}; } }; ``` --- ### 2. 反转链表(Reverse Linked List) **问题描述**:将单链表反转。 **解决思路**:使用三个指针(前驱、当前、后继),逐步反转节点指向。 ```cpp struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {} }; class Solution { public: ListNode* reverseList(ListNode* head) { ListNode *prev = nullptr, *curr = head; while (curr) { ListNode *next = curr->next; curr->next = prev; prev = curr; curr = next; } return prev; } }; ``` --- ### 3. 二叉树的中序遍历(Binary Tree Inorder Traversal) **问题描述**:非递归实现二叉树的中序遍历。 **解决思路**:使用栈模拟递归过程,优先访问左子树[^2]。 ```cpp #include <vector> #include <stack> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; class Solution { public: vector<int> inorderTraversal(TreeNode* root) { vector<int> res; stack<TreeNode*> stk; TreeNode *curr = root; while (curr || !stk.empty()) { while (curr) { stk.push(curr); curr = curr->left; } curr = stk.top(); stk.pop(); res.push_back(curr->val); curr = curr->right; } return res; } }; ``` --- ### 4. 子数组能被K整除Subarray Sums Divisible by K) **问题描述**:统计数组中连续子数组能被K整除的数量。 **解决思路**:前缀+哈希表记录余数频率,时间复杂度$O(n)$[^3]。 ```cpp #include <vector> #include <unordered_map> using namespace std; class Solution { public: int subarraysDivByK(vector<int>& nums, int k) { unordered_map<int, int> map = {{0, 1}}; int ans = 0, sum = 0; for (auto &num : nums) { sum += num; int mod = (sum % k + k) % k; // 处理负数取模 if (map.count(mod)) ans += map[mod]; map[mod]++; } return ans; } }; ``` --- §§ 1. 如何优化两数之问题以处理大数据量? 2. 反转链表的递归实现方法是什么? 3. 二叉树前序后序遍历的非递归实现有何区别? 4. 如何证明前缀+哈希表方法在子数组问题中的正确性? --- **引用说明** : 哈希表优化查找时间的思路常用于数组字符串问题,如两数之二进制求。 [^2]: 栈队列是模拟递归层次遍历的核心数据结构。 : 前缀与哈希表结合可高效解决子数组问题,如LeetCode 974560题。 [^4]: 最短路径算法(如Dijkstra)中更新距离数组的方法与贪心策略相关。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值