单件(singleton)模式作为设计模式的一个典型而且简单的构造型模式, 已经在很多项目的实际开发中被广泛使用, 单件模式要求一个类有且仅有一个实例,然后提供一个全局的访问点.也就是其所有的相关操作都是基于同一个实例的引用.
单件模式的特点:
单件类只能有一个实例
单件类必须自己创建自己的唯一实例
单件类必须给所有其它对象提供这一实例
单件模式的优点:
从逻辑上来讲, 仅有一个实例保证了逻辑的正确性
通过共享减少的使用
减少应为频繁的构造而带来的应用上的损失
下面通过一个简单的例子来说一些单件模式
在我们实际的应用中, 大家都知道数据库的连接资源是非常宝贵的, 通过数据库句柄到数据库的连接是独占的,每次的连接和关闭数据库都是一笔非常大的开销, 那么我们如何在应用程序中来共享数据库句柄呢? 我们可以通过单件模式实现.
以下程序用到三个PHP文件, 程序只是为了展示单件模式,本身不具备任何价值.
MySQL.php
class MySQL {
private $dbhost = 'localhost';
private $dbuser = 'root';
private $dbpass = '123';
private $db = 'test';
public $guid;
//======================================
// 函数: connect()
// 功能: 连接数据库
// 返回:
//======================================
public function __construct()
{
$this->link_id = mysql_connect($this->dbhost, $this->dbuser, $this->dbpass);
$this->guid = md5(uniqid());
if (!$this->link_id)
{
$this->halt("数据库连接失败.请检查连接参数.");
return;
}
if (!mysql_select_db($this->db, $this->link_id))
{
$this->halt("选择数据库".$this->db."失败.");
return;
}
mysql_query("SET NAMES 'utf8'");
}
}
Singleton.php
<?php
class Singleton {
private $_db;
private static $_single = null;
public static function getInstance() {
if (self::$_single === null)
self::$_single = new Singleton();
return self::$_single;
}
function __construct() {
$this->_db = new MySQL();
}
public function db() {
return $this->_db;
}
}
/* End of file */
/* Location: */
Test.php
<?PHP
require_once ('MySQL.php');
require_once ('Singleton.php');
header('content-type:text/html; charset=utf-8');
echo '单件模式____________________________<br />';
$s1 = Singleton::getInstance()->db();
$s2 = Singleton::getInstance()->db();
echo '$s1->guid:'.$s1->guid.'<br />';
echo '$s1->guid:'.$s2->guid.'<br />';
echo ($s1 === $s2) ? 'true' : 'false';
echo '<br />';
echo '直接实例化对象________________________________<br />';
$d1 = new MySQL();
echo '$d->guid:'.$d1->guid.'<br />';
$d2 = new MySQL();
echo '$d1->guid:'.$d2->guid.'<br />';
echo ($d1 === $d2) ? 'true' : 'false';
?>
将这三个文件放到一个目录中, 最后浏览test.php,可以看到
通过单件模式获取的2个对象guid参数任何时候都是相同的,且这两个对象是恒等的.
而直接实例出来的2个DB对象则刚好相反.
通过比较, 相信你已经很轻松的掌握了单件模式的特点.
转载请注明出处:http://www.suiyuan.org
admin 生活
The Rose
by 阿桑

Some say love it is a river
that drowns the tender reed
some say love it is a razor
that leaves your soul to bleed
some say love it is a hunger
and endless aching need
i say love it is a flower
and you its only seed
it’s the heart afraid of breaking
that never learns to dance
it’s the dream afraid of waking
that never takes the chance
it’s the one who won’t be taken
who can not seem to give
and the soul afraid of dying
that never learns to live
when the night has been too lonely
and the road has been too long
and you think that love is only
for the lucky and the strongjust remember in the winter
far beneath the bitter snow
lies the seed that with the sun’s love
in the spring becomes the rose
阅读全文…
admin 音乐
前一篇c#蜂鸣报警系列声音函数
今天要说的是如何实现连续播放报警声音和停止报警.
#region 报警
[DllImport("winmm.dll", EntryPoint = "PlaySound")]
private static extern bool Win32_PlaySound(string pszSound, IntPtr hmod, uint fdwSound);
/// <summary>
/// 播放一个wav音频文件
/// </summary>
/// <param name="path"></param>
/// <param name="asynchronous"></param>
/// <param name="loop"></param>
/// <param name="doNotStopPlay"></param>
public static void PlaySound(string path, bool asynchronous, bool loop, bool doNotStopPlay)
{
Win32_PlaySound(path, IntPtr.Zero, (uint)((asynchronous ?
PlaySoundMessage.SND_ASYNC : PlaySoundMessage.SND_SYNC) | (loop ?
PlaySoundMessage.SND_LOOP : 0) | (doNotStopPlay ?
PlaySoundMessage.SND_NOSTOP : 0) | PlaySoundMessage.SND_FILENAME));
}
/// <summary>
/// 停止播放
/// </summary>
public static void StopSound()
{
Win32_PlaySound(null, IntPtr.Zero, 0);
}
[Flags()]
internal enum PlaySoundMessage
{
SND_SYNC = 0x0000,
SND_ASYNC = 0x0001,
SND_LOOP = 0x0008,
SND_NOSTOP = 0x0010,
SND_FILENAME = 0x00020000
}
#endregion
当例如遥测水位中测量的水位大于预警水位, 通过PlaySound(”alarm8.wav”, true, true, false)方法实现连续报警, 你还可以同时弹出窗口提醒之类的信息.
关闭报警通过方法StopSound()实现就可以了.
admin CSharp
本来想自己写个具体的例子的, 但是太忙了, 又怕转头就忘了, 用的网上的代码.
应该明白的是PHP5中的异常处理和类是紧密结合在一起的, 在进行异常捕捉前对代码中可能出现的异常情况进行判断, 然后抛出异常.
<?php
// PHP 5
require_once('cmd_php5/Command.php');
class CommandManagerException extends Exception{}
class IllegalCommandException extends Exception{}
class CommandManager {
private $cmdDir = "cmd_php5";
function __construct() {
if (!is_dir($this->cmdDir)) {
throw new CommandManagerException("directory error: $this->cmdDir");
}
}
function getCommandObject($cmd) {
$path = "{$this->cmdDir}/{$cmd}.php";
if (!file_exists($path)) {
throw new IllegalCommandException("Cannot find $path");
}
require_once $path;
if (!class_exists($cmd)) {
throw new IllegalCommandException("class $cmd does not exist");
}
$class = new ReflectionClass($cmd);
if (!$class->isSubclassOf(new ReflectionClass('Command'))) {
throw new IllegalCommandException("$cmd is not a Command");
}
return $class->newInstance();
}
}
?>
当我们的类不能找到正确的command目录时,将抛出一个CommandManagerException异常;当在生成Command对象时产生错误,则getCommandObject()方法将抛出一个IllegalCommandException异常。注意存在多个可能导致抛出IllegalCommandException异常的原因(如未找到文件,或在文件中未找到正确的类)。我们将前两个例子结合起来并为IllegalCommandException提供整型的错误标识常量来代表不同类型的出错原因。
现在CommandManager类已经具备了处理这多种出错情况的能力,我们可以增加新的catch语句来匹配不同的错误类型。
代码后半段
<?php
// PHP 5
try {
$mgr = new CommandManager();
$cmd = $mgr->getCommandObject('realcommand');
$cmd->execute();
} catch (CommandManagerException $e) {
die($e->getMessage());
} catch (IllegalCommandException $e) {
error_log($e->getMessage());
print "attempting recovery\n";
// perhaps attempt to invoke a default command?
} catch (Exception $e) {
print "Unexpected exception\n";
die($e->getMessage());
}
?>
看了代码, 应该明白这里和c#直接try…catch不同的是多了个判断的过程. 为什么在C#中不需要, 很简单, C#底层中已经对这些代码进行封装过了.
来个c#打开串口的例子
try
{
if (comPort.IsOpen) comPort.Close();
comPort.BaudRate = int.Parse(_baudRate);
comPort.DataBits = int.Parse(_dataBits);
comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), _stopBits);
comPort.Parity = (Parity)Enum.Parse(typeof(Parity), _parity);
comPort.PortName = _portName;
comPort.Open();
if (this.IsBatch)
DisplayData(MsgType.Normal, "当前模式:批量传输,正在接收数据..\n");
else
DisplayData(MsgType.Normal, "当前模式:实时传输,正在接受数据..\n");
return true;
}
catch (Exception ex)
{
//DisplayData(MsgType.Error, ex.Message);
FormUtility.Alert(ex.Message);
return false;
}
以前对PHP5的异常处理机制了解的不够透彻, 按照C#的方法直接去了才发现还是有不同的. 呵呵, 学习了.
admin PHP
PHP 函数set_error_handler()的用法
<?PHP
function ErrorHandler($errno, $errmsg, $errfile, $errline) {
if ($errno == E_USER_ERROR) {
$msg = "<strong>Custom Error:</strong>$errmsg<br />\n";
$msg .= "File:$errfile<br />\n";
$msg .= "Line Number:$errline<br />\n";
}
echo $msg;
// 记录错误信息
error_log(date("[Y-m-d H:i:s]")." -[".$_SERVER['REQUEST_URI']."] :".$msg."\n", 3, 'log.txt');
// exit(); // 必要时必须终止脚本执行.
}
// set_error_handler()函数用于让用户自定义错误处理函数
// set_error_handler(error_function, error_type)
// error_function 必须, 制定发生错误时运行的函数
// error_type 可选, 规定不同的错误级别提示的不同信息, 默认是"E_ALL"
set_error_handler('ErrorHandler');
$foo = 2;
if ($foo > 1) {
// trigger_error()接收一个错误信息和一个常量作为参数,
// 常量为E_USER_ERROR -> a fatal error
// E_USER_WARNING -> a non-fatal error
// E_USER_NOTICE -> a report that may not represent an error
trigger_error("A custom error has been trigglered", E_USER_ERROR);
}
?>
PHP 函数set_exception_handler()的用法
<?php
function ExceptionHandler($e) {
echo "<strong>Exception:</strong>".$e->getMessage();
echo "Stack Trace String:".$e->getTraceAsString();
}
// set_exception_handler()函数用于让用户自定义异常处理函数
// set_exception_handler(exception_function)
// 该函数需要抛出的exception对象最为参数
// 在这个异常处理程序被执行后, 脚本会停止执行
set_exception_handler('ExceptionHandler');
throw new Exception('Uncaught Exception occurred');
?>
admin PHP
Smarty, PHP的一个非常出名的模板引擎, 很少用, 最近用了一点, 记录一些心得以备日后查阅.
1. 使用Smarty进行循环嵌套
// 在这里定义$sec1为一个二维数组
$sec1 = $db->fetchAll("select * from category");
for($i=0; $i<count($sec1); $i++) {
$sec1[$i]['news'] = $db->fetchAll("select * from news where cid = ".$sec1[$i]['id']." order by id desc limit 0, 5");
}
$smarty->assign('sec1', $sec1);
$smarty->left_delimiter = "<{";
$smarty->right_delimiter = "}>";
$smarty->display('news.html');
// 模版文件
<{section name=sec1 loop=$sec1}>
<div class="inner">
<h1><a href="/category/<{$sec1[sec1].id}>.html"><{$sec1[sec1].name}></a></h1>
<ul>
<{section name=sec2 loop=$sec1[sec1].news}>
<li>
<a href="/news/<{$sec1[sec1].news[sec2].id}>.html" target="_blank">
<{$sec1[sec1].news[sec2].title}>
</a>
</li>
<{/section}>
</ul>
</div>
<{/section}>
2. Smarty对于类似分页情况时的多参数缓存
我们都知道可以通过$smarty->display(’NewsList.tpl’, $page)这样来实现类似与NewsList.php?page=1这样URL结构相同的情况缓存. 但是如果情况是NewsList.php?cid=1&Page=1这样呢? 或许大家也知道, 但是我今天在网上查阅了一下才知道原来这么简单,$smarty->display(’NewsList.tpl’, “cid:{$cid}-page:{$page}”)就可以了. 呵呵
admin PHP smarty
Recent Comments