今天在项目开发中遇到一个“天坑”,没错,一个耗了大半天也没解决的bug,最好幸好 @破鱼缸 的点拨,茅塞顿开。记录一下
####具体业务就不说了,问题重现步骤抽象如下:
新建一个php文件,test.php
要达到目的可以直接把session_id 对应的内容置为空即可
今天在项目开发中遇到一个“天坑”,没错,一个耗了大半天也没解决的bug,最好幸好 @破鱼缸 的点拨,茅塞顿开。记录一下
####具体业务就不说了,问题重现步骤抽象如下:
新建一个php文件,test.php
要达到目的可以直接把session_id 对应的内容置为空即可
当活跃用户比较多的时候,默认的session处理机制显然就不那么好了
session放在redis里面可以 解决文件读写效率低和跨服务器session读取不到的问题
下面是使用redis处理redis的demo,已在 5.3.3 下测试通过
昨晚堂兄打电话传来噩耗,大表兄,姑妈的长子突然离世……晴空霹雳,一个活生生亲人就这样突然离开了,连见最后一面的机会都没有。脑子一遍空白,整个人已经痛苦到不能思考…
mark~在新浪的时候,一个小组技术分享会
###什么是设计模式?
设计模式是一套代码设计经验的总结
###为什么要提倡“Design Pattern“
根本原因是为了代码复用,增加可维护性
###几个误区
设计模式并非起源于计算机科学,而是建筑学
###设计模式并非只有23种
设计模式并不只适用于面向对象
###面向对象设计的5大原则
####1)单一职责原则
避免相同的职责分散到不同的类中;避免一个类承担太多的职责
eg:活字印刷术,拆分成词?
工厂模式,只负责生产对象,但是不负责对象的具体实现
####2)接口隔离原则
一个类对另一个类的依赖性应当是建立在最小的接口上的;客户端程序不应该依赖它不需要的接口方法
eg: 缓存基类,(连接、关闭,get、set操作)但是不应该有(zset、zget)此类操作
多继承防止胖接口, 或者考虑组合
####3)开放封闭原则
一个模块在可扩展性方面应该是开放的,在可更改方面应该是封闭的
eg: 电脑组装的案例
子类必须能够替换掉它们的父类型、并出现在父类能够出现的任何地方
eg: 手机 到 智能机 (最基本的电话短信功能,可以添加任何其它功能 mp3,导航等,它依然是手机,但是如果它不能打电话发短信呢?最多是个pad)
####5)依赖倒置原则
上层模块不应该依赖于下层模块 ,它们共同依赖于一个抽象(父类不能依赖于子类,它们都要依赖抽象类),抽象不应该依赖于具体,具体应该依赖于抽象
因为抽象是相对稳定,不易变化的
eg: 给前端同事提供接口,基类两个抽象方法 (接收并检查参数,返回约定格式的结果) 那么不管你是怎么具体来实现的,谁来实现,都应该依赖于这个抽象
###设计模式的分类,总体来说设计模式分为三大类:
创建型模式,共五种
工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种
策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
下面与大家分享10种常用的设计模式
1、单例模式
保证某个类只有一个实例
class MysqlStorage {
private static $_instance = null;
public function __constant() {
// do something
}
public static function getInstance() {
if(self::$_instance == null ) {
self::$_instance = new MysqlStorage;
}
return self::$_instance;
}
}
Q2:php是非常驻内存的,脚本执行完之后就释放所有内存,那么这个单例模式的好处是什么呢?
2、工场模式
创建对象的类
abstract class Operation {
abstract public function operate($num1, $num2);
}
class operationAdd extends Operation {
public function operate($num1, $num2) {
return $num1 + $num2;
}
}
class operationSub extends Operation {
public function operate($num1, $num2) {
return $num1 - $num2;
}
}
// ……
class Factory {
public static function createObj($operate) {
$class = “operation”.ucfirst(strtolower($operate));
return new $class;
}
}
$test = Factory::createObj(‘add’);
echo $test->operate(23, 0);
如果我们再添加一个 取余运算,传统的方法会让switch分支添加,代码庞杂,不易维护。如果用工厂模式直接再添加一个运算类继承基类,这样就避免修改原来的代码,很好的实现 开放封闭原则、而工厂类只负责对象的生产,而不负责对象的具体实现,也体现了单一职责原则。
3)、抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
他与工厂方法模式的区别就在于,工厂模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。
也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族
抽象工厂模式所提供的一系列产品就组成一个产品族;
abstract class Engine {
public function get(){}
}
//轿车引擎
class CarEngine extends Engine{
public function get(){
echo ‘get car engine’;
}
}
//巴士引擎
class BusEngine extends Engine{
public function get(){
echo ‘get bus engine’;
}
}
//车轮
abstract class Wheel{
public function get(){}
}
//轿车车轮
class CarWheel extends Wheel{
public function get(){
echo 'get car wheel';
}
}
//巴士车轮
class BusWheel extends Wheel{
public function get(){
echo 'get bus wheel';
}
}
//工厂
abstract class Factory {
public static function create($class){}
}
//轿车工厂
class CarFactory extends Factory{
public static function create($class){
$class = ‘Car’.$class;
return new $class;
}
}
//巴士工厂
class BusFactory extends Factory{
public static function create($class){
$class = ‘Bus’.$class;
return new $class;
}
}
//使用例子:创建轿车的轮子,巴士的引擎
CarFactory::create(“Wheel”)->get();
BusFactory::create(“Engine”)->get();
适用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
4)、观察者模式
定义对象之间一对多的关系,当被观察的对象状态发生改变的时候,所有观察它的对象都会得到提醒并做出相应的改变
class Location{
private $_observers = array();
public function register($sub){ / 注册观察者 /
$this->_observers[] = $sub;
}
public function trigger(){ / 统一得到更新 /
if(!empty($this->_observers)){
foreach($this->_observers as $observer){
$observer->update();
}
}
}
}
interface Observerable{
public function update();
}
class Subscriber implements Observerable{
public function update(){
echo “Callbackn”;
}
}
$location->register(new Subscriber());
$location->register(new Subscriber1());
$location->register(new Subscriber2());
$paper->trigger();
eg: 这是一种很常见的设计模式,比如美团客户端。 位置对象(获取当前的地理坐标),酒店Obj、美食Obj、KTV Obj等都观察位置对象,如果位置对象发生改变,那些这些观察它的对象也要相应发生变化
5)、策略模式
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
interface yueHui {
public function eat();
}
//策略A
class StrategyA implements yueHui {
public function eat() {
echo “我们去吃海底捞吧!”;
}
}
class StrategyB implements yueHui {
public function eat() {
echo “我们去吃麻辣烫吧,6块钱的那种!”;
}
}
// 环境类
class ownContext {
private $_strategy = null;
public function __construct(yueHui $strategy) {
$this->_strategy = $strategy;
}
public function eat() {
$this->_strategy->eat();
}
}
// 含蓄性妹子,使用策略A
$oc = new ownContext(new StrategyA);
$oc->eat();
// 奔放性妹子,使用策略B
$oc = new ownContext(new StrategyB);
$oc->eat();
6) 迭代器模式
迭代器模式提供一种访问一个容器对象中的各个元素,而又不暴露其内部细节的方法
提供一种通过对象集合或对象数组封装迭代的方法。如果需要遍历集合中不同类型的对象,则使用这种模式尤为便利。
使用迭代器可以对不同数据结构的集合封装,外部只需调用迭代器提供的接口即可,提高了应用的可扩展性。
A、通过遍历数组的方法去遍历对象 http://php.net/manual/zh/language.oop5.iterations.php
a、直接遍历
b、继承iterator接口,实现 current(), key(), next(), rewind(), valid() 这几个方法
c、实现IteratorAggregate 接口以替代实现所有的 Iterator 方法
IteratorAggregate 只需要实现一个方法IteratorAggregate::getIterator(),其应返回一个实现了 Iterator 的类的实例。
d、使用反射api
$reflect = new ReflectionObject($student);
$props = $reflect->getProperties(); // 获取属性列表
$m = $reflect->getMethods(); // 获取方法列表
e、使用class函数
get_object_vars($student);
get_class_methods(get_class($student));
B、遍历文件夹(递归,实现Iterator接口)
a、递归
b、使用DirectoryIterator类(已经实现了Iterator接口)
$dir = new DirectoryIterator(dirname(FILE));
foreach($dir as $fileinfo) {
if(!$fileinfo->isDir()) {
echo $fileinfo->getFilename(), “t”, $fileinfo->getSize(), PHP_EOL;
}
}
7) 命令模式
将一个请求封装为一个对象,从而你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。
eg: 用户请求action(可能是 login、register、logout等操作),命令模式可以干掉大量的if else 操作(或者 switch)
interface ICommand {
function onCommand($name, $args);
}
class LoginCommand implements ICommand {
public function onCommand($name, $args) {
if ($name != ‘login’) {
return false;
} else {
// 执行登录命令
}
}
}
class RegisterCommand implements ICommand {
public function onCommand($name, $args) {
if ($name != ‘register’) {
return false;
} else {
// 执行注册命令
}
}
}
class CommandChain {
private $_commands = array();
public function addCommand($cmd) {
$this->_commands []= $cmd;
}
public function removeCommand() {
// 删除命令
}
public function runCommand($name, $args) {
foreach($this->_commands as $cmd) {
if ($cmd->onCommand($name, $args)) return;
}
}
}
$cc = new CommandChain();
$cc->addCommand(new LoginCommand());
$cc->addCommand(new RegisterCommand());
$cc->runCommand(‘login’, array(‘username’, ‘password’));
$cc->runCommand(‘register’, array(‘username’, ‘password’));
8)建造者模式
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示
class Product {
public $_type = null;
public $_price = null;
public $_color = null;
public function setType($type) {
echo ‘set the type of the product,’;
$this->_type = $type;
}
public function setPrice($price) {
echo ‘set the price of the product,’;
$this->_price = $price;
}
public function setColor($color) {
echo ‘set the color of the product,’;
$this->_color = $color;
}
}
$config = array( ‘type’ => ‘shirt’, ‘price’ => 100, ‘color’ => ‘red’);
class ProductBuilder
{
public $_config = null;
public $_object = null;
public function ProductBuilder($config) {
$this->_object = new Product();
$this->_config = $config;
}
public function build() {
echo ‘
Using builder pattern:
‘;
$this->_object->setType($this->_config[‘type’]);
$this->_object->setPrice($this->_config[‘price’]);
$this->_object->setColor($this->_config[‘color’]);
}
public function getProduct() {
return $this->_object;
}
}
$objBuilder = new ProductBuilder($config);
$objBuilder->build();
$objProduct = $objBuilder->getProduct();
eg : 在创建不同的 数据库对象 实例的时候,构建的过程是一样的,但是可能因为db不同最后创建的实例不同
9)外观模式
为一个分层或一个子系统创建一个单一的入口 , 外观设计模式隐藏了调用对象的复杂性。
eg: liangliang 包接口
class SubSystem1{
public function method1(){
echo ‘ SubSystem1 method1’;
}
}
class SubSystem2{
public function method2(){
echo ‘ SubSystem2 method2’;
}
}
class SubSystem3{
public function method3(){
echo ‘ SubSystem3 method3’;
}
}
class Facade{
private $_object1 = null;
private $_object2 = null;
private $_object3 = null;
public function __construct(){
$this->_object1 = new SubSystem1();
$this->_object2 = new SubSystem2();
$this->_object3 = new SubSystem3();
}
public function methodA(){
echo ‘Facade methodA ‘;
$this->_object1->method1();
$this->_object2->method2();
}
public function methodB(){
echo ‘Facade methodB ‘;
$this->_object2->method2();
$this->_object3->method3();
echo ‘
‘;
}
}
$facade = new Facade();
$facade->methodA();
$facade->methodB();
10) 备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到保存的状态
类对于对象而言是个模具, 同一类对象是具有相同的属性和方法,只是它们的属性值是不同的
eg: 爱迪生造电灯,不停的测试,材料为钨丝的时候感觉效果比较好,这个时候又把材料切换成bbb这种……最后还是发现铁丝的比较好,于是要还原原来的状态
class Light {
private $state = null;
public function __construct($state) {
$this->_state = $state;
}
//创建备忘录,将当前要保存的信息导入并实例化备忘录
public function createMemento() {
return new Memento($this->state);
}
//恢复备忘录,将Memento导入并将相关数据恢复
public function setMemento(Memento $memento) {
$this->state = $memento->state;
}
// 设置状态
public function setStatus($status) {
$this->_status = $status;
}
//展示状态数据
public function show() {
echo ‘当前状态是:’.$this->_state;
}
}
//备忘录类Memento
class Memento {
private $state;
public function __construct($state) {
$this->$_state = $state;
}
public function getState() {
return $this->_state;
}
}
//管理者类Caretaker
class Caretaker {
private $memento;
public function __set($key, $value) {
$this->$key = $value;
}
public function __get($key) {
if(isset($this->$key)) {
return $this->$key;
} else {
return NULL;
}
}
}
$light = new Light();
$light->setStatus(“钨”);
$light->show(); //初始状态为钨,比较好的状态
//创建备忘录并保存状态
$caretaker = new Caretaker();
$caretaker->memento = $light->createMemento();
//更改状态
$light->state = ‘铁’;
$light->show();
//恢复到原始状态
$light->setMemento($caretaker->memento);
$light->show();
?>
最后,感谢大家! 多有不足之处,烦请拍砖斧正…
mark一下
折腾了大半天,终于把博客迁移到git page. 为了跟进时代我也是蛮拼的!