设计模式,简单的说,是代码设计的经验,目的是解决现在和未来代码中存在的非需求功能问题
原则不是万能的,原则即是约束,你选择坚持原则,就接受了约束,也享受它带来的好处。
原则 | 解决的问题 |
---|---|
单一职责原则 | 边界 |
里氏替换原则 | 继承 |
依赖倒置原则 | 依赖 |
接口隔离原则 | 安全 |
迪米特原则 | 封装 |
开闭原则 | 变化 |
1、单一职责
定义:应该有且仅有一个原因引起类的变更
说人话:"这事不归我们部门管的"。这个原因是指自己负责的业务原因,不是自己的业务接口不实现,如果需要让你实现,先跟他声明自己的职责和这个接口是否数据自己的职责,遇到边界业务可以单独建边界类
class User{}//用户类,负责用户数据相关的逻辑
class Order{}//订单类,负责订单相关的逻辑
class ServiceInfo{}//服务类,负责服务相关的逻辑
class Tongji{} //统计类,边界类,关联User和Order类
2、里氏替换原则
定义:继承必须确保超类所拥有的性质在子类中仍然成立。通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
说人话:"你父母是这样教你的?"父类的某个方法,在父类内被其他方法调用的,不能重写父类方法。否则可以重写。
不适合重写父类方法的情况:
//父类
abstract class Father{
function off(){
echo "关灯"
}
function sleep(){
$this->off();
echo "睡觉"
}
abstract function seeTV();
}
//子类张三
class ZhangSan extends Father{
//新增方法
function on(){
echo "开灯"
}
//看电视
function seeTV(){
$this->on();
echo "看电视新闻"
}
}
//子类李四
class LiSi extends Father{
//重写父类方法,这个方法的重写,在父类里是没问题的,但是在父类的sleep中确产生程序错误,
function off(){
echo "开灯"
}
function seeTV(){
$this->off();
echo "看电视动画片"
}
}
$zhangsan = new ZhangSan();
$lisi = new LiSi();
//张三
$zhangsan->seeTV();//开灯,看电视新闻
$zhangsan->sleep();//关灯,睡觉
//李四
$lisi->seeTV();//开灯,看电视动画片
$lisi->sleep();//开灯,睡觉。因为重写了父类的off方法,造成父类其他方法程序错误
3、依赖倒置原则
定义:
● 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
● 抽象不应该依赖细节;
● 细节应该依赖抽象。
说人话:你爱的从来不是我,而是你理想中的人。正置:类的声明或者依赖是具体的子类。倒置:类的声明或者依赖是父类或者接口。从依赖子类变为依赖父类,这就是依赖的倒置
class Parent {
//叫某人睡觉
function someOneSleep(Father $someOne){
$someOne->sleep();
}
//叫张三睡觉
function zhangSanSleep(ZhangSan $zhangsan){
$zhangsan->sleep();
}
//叫李四睡觉
function liSiSleep(LiSi $lisi){
$lisi->sleep();
}
}
class Mother extends Parent{
}
//client 高层业务,依赖parent抽象
Parent $parent = new Mother();//
ZhangSan $zhangsan = new ZhangSan()
LiSi $lisi = new LiSi();
$parent ->someOneSleep($zhangsan);
$parent ->someOneSleep($lisi);
以后如果响应国家号召生了3胎王麻子,只要调用someOneSleep就行,不用在新增WangMaZiSleep
下次还可以换成爸爸叫他们睡觉,下面的代码都不用变
这个场景就抽象为:父母叫孩子睡觉,适用于所有家庭
如果不抽象:就是张三家的妈妈叫张三,李四睡觉
4、接口隔离原则
定义:
● Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口。)
● The dependency of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上。)
说人话:"交浅言莫深"。客户只需要1个方法,不要提供一个包含了10个方法接口给他。
//秘密接口
interface mimi{
//女朋友是谁
function girlFriend();
//工资多少
function salary();
//京东密码
function jdPassword();
//蜂巢取件码
function getCode();
}
class ZhangSan implements mimi{
...实现接口
}
//韵达快递
class YunDaKuaiDi{
//通知取件
function qujian(mimi $zhangsan){
echo $zhangsan->getCode();//获取取件码
//echo $mimi->girlFriend();
}
}
取个快递,你把你女朋友是谁都告诉别人了,这合适吗?不合适
所以,把getCode从秘密接口隔离出来
interface kuaidi{
function getCode();
}
class YunDaKuaiDi{
//通知取件
function qujian(kuaidi $zhangsan){
echo $zhangsan->getCode();//获取取件码
}
}
5、迪米特法则
定义:一个对象应该对其他对象有最少的了解
说人话:"我不看过程,只要结果"
class ZhangSan{
function saodi(){
echo "扫地"
}
function tuodi(){
echo "拖地"
}
function daolaji(){
echo "倒垃圾"
}
function clearRoom(Father $father){
$this->saodi();
$this->tuodi();
$this->daolaji();
$father->notice();//打扫完房间,告诉爸爸
}
}
class Mother{
//妈妈叫张三清理房间
function clearRoom(ZhangSan $zhangsan){
$zhangsan->saodi();//叫张三扫地
$zhangsan->tuodi();//叫张三拖地
$zhangsan->daolaji();//叫张三倒垃圾
//妈妈已经不想说话
}
}
class Father{
function clearRoom(ZhangSan $zhangsan){
$zhangsan->clearRoom($this);//叫张三打扫房间
//爸爸去玩游戏了
}
function notice(){
echo "房间打扫完了"
}
}
//这一比较,明显爸爸更省心
6、开闭原则
定义:
Software entities like classes,modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。)
说人话:"长大后,你发现你不能改变别人,只能改变你自己"
class girlFriend{
function maifang(){
echo "在北京买房"
}
}
class boyFriend extends girlFriend{
//男朋友想在老家买房
function maifang(){
parent::maifang()."不现实,回老家买吧"
}
}