php模式之装饰器模式2

在上一篇文章中,介绍了如何在代码架构之初,为了以后的扩展方便做的考虑,那么在现实中大部分的情况不是如此,那么我们需要重构这块么?不一定,今天我们使用另一种方式来实现装饰器。
假设现在我们处在产品的第二个阶段,有下面第一阶段代码来实现需求

class User{
    function loadData(){
        $res = 'load ...' . PHP_EOL;
        return $res;
    }
}

还是同样的,怎么在不改变调用逻辑 和 User::loadData 的基础上来扩展呢。php给我们提供了一个方案:Trait

//首先,我们先实现一个trait
trait Count{
     function loadData(){
         $res = parent::loadData();
         //count 的逻辑
         return $res;
     }
}
//接下来,把User类更名为UserBase
class UserBase {
    function loadData(){
        echo 'load ...' . PHP_EOL;
    }
}
//紧接着,重新写一个User类来继承 UserBase(如果不这样做,代码使用者估计打死你的),并且使用 Count
class User extends UserBase{
     use Count;
}

这样,我们就完成装饰器的功能,甚至能在不改变原来代码的情况下偷梁换柱做一些更加彻底的操作。

发表在 php, 设计模式 | php模式之装饰器模式2已关闭评论

php模式之装饰器模式1

装饰器模式,也称修饰器模式。目的是给现有的对象增加或修改成新逻辑。说人话就是不改变对象的情况下,给对象的某个操作增加前置操作或者后置操作(当然也有可能改变操作的逻辑)。
举个栗子:
我们在操作数据库的时候会从数据库拉取数据,拉取数据的动作是 loadData,那么就可以针对loadData操作进行“装饰器”的封装。
1. 实现loadData接口,接口这里的目的是所有加载数据的地方都有一个统一的规范

interface loadDataInterface{
    function loadData($where);
}

2. 实现上面的接口来封装model层

//db 是数据库的封装
class user extends db implements loadDataInterface{
    function loadData($where){
        //$this->db->query($where)
    }
}

(一般情况下,做完上面两部,就完成了第一阶段的需求,如果后续阶段,需要在拉取用户数据后要执行特定的操作,比如说拉取了多少数据,怎么办呢?继续往下。。。)

3. 做一个装饰器

//装饰器封装了前置操作,和后置操作
abstract class loadDataDecorator implements loadDataInterface{
    public $handle = null;
    public $where = null;
    function __construct(loadDataInterface $handle){
        $this->handle = $handle;
    }

    abstract function loadBefore();
    abstract function loadAfter();

    function loadData($where){
        $this->where = $where
        $this->loadBefore();
        $this->handle->loadData($this->where);
        $this->loadAfter();
    }
}

4. 实现拉取数据后记录数量的操作

class loadDataAfterCount extends loadDataDecorator{
    //因为装饰器一并封装了前置操作,这里留空就行
    function loadBefore(){
        //do nothing
    }

    function loadAfter(){
        //$this->db->queryCount($this->where)
    }
}

5. 使用装饰器

$userModel = new loadDataAfterCount(new User)
$userModel->loadData();

装饰器带来的思考:
有些同学可能注意到了,如果要实现拉取用户后记录多少数据被拉取,那么直接改 User::loadData 多方便,一句话的事,为啥要费老大的劲做真么多的操作呢?!其实封装的目的是代码(或者说逻辑)的重复可用,现在需要拉取用户后记录数据量,那么如果来去其他的数据后也记录呢?如果不仅仅是记录还有更多的更复杂的逻辑呢?这个时候,封装的好处就尤为明显了,只需在需要添加逻辑的位置“装饰”一下,这个世界就又那么美丽了~

发表在 设计模式 | 标签为 , , , , , , | php模式之装饰器模式1已关闭评论

Python 字符串 str 和 bytes

在python3中,已经把str和bytes做了明显的分别,两者之间不能混用(纬度不一样),编程中直接声明的字符串使用的是unicode,在字符串存储或者传输时使用的是字节流(比特流),这个时候Python帮你做unicode转bytes。如果不需要Python帮你这么做。你可以直接使用字节的方式声明。

//str 转 bytes
>>> s = '您好'
>>> type(s)
<class 'str'>
>>> s
'您好'
>>> b = bytes(s, encoding='utf-8')
>>> type(b)
<class 'bytes'>
>>> b
b'\xe6\x82\xa8\xe5\xa5\xbd'

//bytes 转 str
>>> b1 = b'\xe6\x82\xa8\xe5\xa5\xbd'
>>> b1
b'\xe6\x82\xa8\xe5\xa5\xbd'
>>> s1 = str(b1, encoding='utf-8')
>>> s1
'您好'
发表在 Python | Python 字符串 str 和 bytes已关闭评论

mysql 比较工具(MAC)

1. 安装软件
a.(https://dev.mysql.com/downloads/connector/python/)

brew cask install mysql-connector-python

b.(https://downloads.mysql.com/archives/utilities/)

brew cask install mysql-utilities

2. 比较两个数据库的方法(可以比较两个数据库表的差别)

mysqldiff --server1=user:pass@host:port:socket --server2=user:pass@host:port:socket db1:db2

3. 比较两个表的方法,以表1为比较源,以alter sql为输出,结果为表2执行什么语句可以变成表1

mysqldiff --server1=user:pass@host:port:socket --server2=user:pass@host:port:socket --changes-for=server2 --difftype=sql db1.table:db2.table

4.安装的mysql工具包括如下,有时间自己尝试:
mysqlauditadmin
mysqlauditgrep
mysqldbcompare
mysqldbcopy
mysqldbexport
mysqldbimport
mysqldiff
mysqldiskusage
mysqlfabric
mysqlfailover
mysqlfrm
mysqlindexcheck
mysqlmetagrep
mysqlprocgrep
mysqlreplicate
mysqlrpladmin
mysqlrplcheck
mysqlrplms
mysqlrplshow
mysqlrplsync
mysqlserverclone
mysqlserverinfo
mysqluc
mysqluserclone

发表在 mysql | mysql 比较工具(MAC)已关闭评论

mysql 事务注意事项

再mysql执行事务中,禁止执行DDL 和 DCL语句,防止程序不可控!!
这种隐式的提交将把显示开启的事务也给提交。所以在事务中执行非DML的语句,将自动提交事务。之后的语句将在非事务中运行

对于DDL(create、alter、drop等开头的语句)和DCL(grant、revoke语句)事务,在执行每条语句之前和之后,MySQL会自动执行一条COMMIT语句,因此事务是自动开始和结束的。自动提交打开或者关闭对这些事务没有影响
对于DML事务,在自动提交关闭的情况下,事务的开始分为隐式开始和显式开始:
隐式开始:程序的第一条DML语句执行时或者在COMMIT或ROLLBACK语句之后执行第一条DML语句时,自动开始一个新的事务
显式开始:发出STRAT TRANSACTION语句。该语句会自动关闭自动提交,当事务结束后,autocommit变量恢复到原来的值

发表在 mysql | 标签为 , | mysql 事务注意事项已关闭评论

mysql 检查死锁日志

show engine innodb status
防止死锁的最简单的办法就是永远使用主键更新一条数据。

发表在 mysql | mysql 检查死锁日志已关闭评论

查看所有人某个命令是否被执行过

#!/bin/bash
#mac 用户目录,linux改成 home
 for user in `ls /Users`
 do

#zsh 的命令历史存放文件
     file="/Users/"$user"/.zsh_history"
     if [ -e $file ]; then
         for a in `grep  $1 $file`
         do
             echo $user" "$a
         done
     fi
 done

把上述代码保存到 myhistory中,然后

chmod +x myhistory

要查看谁执行过 ls 命令:

./myhistory ls
发表在 Shell | 查看所有人某个命令是否被执行过已关闭评论

匿名函数和闭包的区别

匿名函数是“函数”,闭包是一个关注的是变量所处的一个特殊环境的一个代码结构

//这是一个匿名函数,这个匿名函数返回一个闭包
function(){
   return function(){}
}

函数在程序执行的时候,内部的变量会随着使用的结束而释放(因为函数内部的变量只有函数内部能访问,外部是访问不了的,不释放的话也没有意义,还浪费资源)。但是在函数式编程里打破了这个规则,因为“函数式编程”里函数是“一等公民”,他和其他类型的值一样可以被复制给变量,所以函数也能返回一个函数,这个被返回函数使用了所依托函数的内部变量,所以依托函数使用后,也不能把变量释放,这种特殊变量(也称之为“自由变量”)所在的函数被叫做“闭包”。
闭包和匿名函数其实是两个概念,但是使用上很容易弄混。比如:

//把匿名函数当作闭包使用
for(var i = 0; i < 5; i++){
    setTimeout(function(){console.log(i)}, 1000)
}
//上面的想法初期的想法是:1秒钟之后输出0,1,2,3,4,但是结果是输出了5个5
//把上面的函数等价下面的写法,这样你就能看懂了,其实你打印的一直是最外面的i
var func = function(){console.log(i)}
for(var i = 0; i < 5; i++){
    setTimeout(func, 1000)
}

//---------下面的是闭包正确的写法---------
var func = function(i){
    return function(){
        console.log(i)
    }
}
for(var i = 0; i < 5; i++){
    setTimeout(func(i), 1000)
}
//---------当然也放到一起----------------
for(var i = 0; i < 5; i++){
    setTimeout((function(i){
        return function(){
            console.log(i)
        }
    })(i), 1000)
}

//---------再当然匿名函数的话还能这么实现---------
for(var i = 0; i < 5; i++){
    let j = i//这里是let,不是var,如果是var将得到5个4,
    setTimeout(function(){console.log(j)}, 1000)
}
发表在 js, 程序基础 | 标签为 | 匿名函数和闭包的区别已关闭评论

preventDefault,stopPropagation,stopImmediatePropagation 区别

event.preventDefault
阻止浏览器默认行为,例如:点击a链接,浏览器会跳转到链接,这个“跳转到链接”就是浏览器默认行为。
https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault

event.stopPropagation
阻止事件冒泡
https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopPropagation

event.stopImmediatePropagation
一个dom的一个事件可以有多个监听,当一个事件被触发,则这些监听事件会按顺序执行,这个按函数阻止其他监听事件执行
https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopImmediatePropagation

引申阅读:
https://zh.javascript.info/ui
https://zh.javascript.info/bubbling-and-capturing

发表在 js | preventDefault,stopPropagation,stopImmediatePropagation 区别已关闭评论

webpack 设置局域网内他人可以访问

首先,我先问一下,网上说那些把host设置成0.0.0.0, 或者说 使用 disableHostCheck:true, 或者说 使用allowedHosts参数的,你们怎么是让别人访问的?别人的浏览器输入什么才能访问到你的webpack服务器呢?

我的方法,先知道自己机器的IP地址,然后host指向自己的IP地址,这样,局域网内的其他人就可以通过这个ip地址和端口访问的webpack服务器了。

发表在 webpack, 前端 | webpack 设置局域网内他人可以访问已关闭评论