Single-Responsibilitiy Principle(SRP):对一个类而言,应该仅有一个引起它变化的原因。如果存在多于一个动机去改变一个类,那么这个类就具有多于一个的职责,就应该把多余的职责分离出去,再去创建一些类来完成每一个职责。
举个例子:一个人身兼数职,而这些事情相关性不大,甚至有冲突,那他就无法很好的解决这些问题职责,应该分到不同的人身上去做。
class Animal
{
public function breathe($animal)
{
echo $animal . "在空气中呼吸
";
}
}
class Program
{
public function main()
{
$animal = new Animal();
$animal->breathe("牛");
$animal->breathe("羊");
// 鱼是在水中呼吸,因此这样不妥
$animal->breathe("鱼");
}
}
#------------------- 修正 ---------------------#
class Aquatic
{
public function breathe($animal)
{
echo $animal . "在水中呼吸
";
}
}
class Program2
{
public function main()
{
$animal = new Animal();
$animal->breathe("牛");
$animal->breathe("羊");
// 鱼是在水中呼吸
$aquatic = new Aquatic();
$aquatic->breathe("鱼");
}
}
单一职责原则是实现高内聚低耦合的最好方法,没有之一。
Liskov Substitution Principle:子类可以扩展父类的功能,但是不能改变父类原有的功能。
在第一条原则开放封闭原则中,主张“抽象”和“多态”。维持设计的封装性“抽象”是语言提供的功能,“多态”由继承语意实现。因此如何去度量继承关系中的质量?
答案是:继承必须明确确保超类(父类)所拥有的性质在子类中仍然成立。
在面向对象的思想中,一个对象就是一组状态和一系列行为的组合体。状态是对象的内在特性,行为是对象的外在特性。LSP表述的就是在同一继承体系中的队形应该具有共同的行为特征。
class A
{
public function subtract($a, $b)
{
return $a - $b;
}
public function quadrature($a, $b)
{
return $this->subtract($a, $b) * 100;
}
}
// 这种是修改,而非拓展
class B extends A
{
public function subtract($a, $b)
{
return $a + $b;
}
public function quadrature($a, $b)
{
return $this->subtract($a, $b) * 100;
}
}
#------------------拓展--------------------#
abstract class D
{
public abstract function subtract($a, $b);
public function quadrature($a, $b)
{
return $this->subtract($a, $b) * 100;
}
}
// 通过子类继承实现抽象方法达到拓展目的
class E extends D
{
public function subtract($a, $b)
{
return $a + $b;
}
}
class F extends D
{
public function subtract($a, $b)
{
return $a - $b;
}
}
Dependence Inversion Principle(DIP):是一个类与类之间的调用规则。这里的依赖就是代码中的耦合。高层模块不应该依赖底层模块,二者都应该依赖其抽象了;抽象不依赖细节;细节应该依赖抽象。接口编程。
主要思想就是:如果一个类中的一个成员或者参数成为一个具体的类型,那么这个类就依赖这个具体类型。如果在一个继承结构中,上层类中的一个成员或者参数为一个下层类型,那么就是这个继承结构高层依赖底层,就要尽量面向抽象或者接口编程。
举例:存在一个Driver类,成员为一个Car对象,还有一个driver()方法,Car对象中有两个方法start()与stop()。显然Driver依赖Car,也就是说Driver类调用了Car类中的方法。但是当增加Driver类对于Bus类的支持时(司机有需要开公交车),就必须更改Driver中的代码,就破坏了开放封闭原则。根本原因在于高层的的Driver类与底层的Car类仅仅的耦合在一起的。解决方法之一就是:对Car类和Bus类进行抽象,引入抽象类Automoble。而Car和Bus则是对Automobile的泛化。
经过这样的改造发现,原本的高层依赖底层,变成了高层与底层同时依赖抽象。这就是依赖倒转原则的本质。
优点:
/*
* 依赖倒置原则
*/
class Book
{
public function getContent()
{
return "在很久很久以前";
}
}
class Newspaper
{
public function getContent()
{
return "php是最好的语言";
}
}
class Mother
{
public function narrate(Book $book)
{
echo $book->getContent();
}
}
$m = new Mother();
$m->narrate(new Book());
#----------------改正----------------#
interface IReader
{
public function getContent();
}
class Bookl implements IReader
{
public function getContent()
{
return "在很久很久以前";
}
}
class Newspaperl implements IReader
{
public function getContent()
{
return "php是最好的语言";
}
}
class Motherl
{
public function narrate(IReader $iRead)
{
echo $iRead->getContent();
}
}
$ml = new Motherl();
$ml->narrate(new Bookl());
$ml->narrate(new Newspaperl());
接口隔离原则(Interface Segregation Principle):用于恰当的划分角色和接口,具有两种含义:1、用户不应该依赖它不需要的借口;2、类间的依赖关系应该建立在最小的的接口上。
将这两个定义概括为一句话:建立单一接口,代替庞大臃肿的接口。通俗来说就是:接口尽量细化,同时保证接口中的方法尽量的少。一个接口中包含太多的行为时,会导致它们与客户端的不正常依赖关系,要做的就是分离接口,从而实现解耦。
回到上述的单一职责原则,要求行为分离接口接口细化,感觉有些相同。但实际上,单一职责原则要求类与接口的职责单一,注重的是职责,没有要求接口尽量的少。
在接口隔离原则中,要求尽量使用多个专门的接口。专门的接口也就是提供给多个模块的接口。提供给几个模块就应该有几个接口,而不是建立一个臃肿庞大的接口,所有的模块都可以访问。
但是接口的设计是有限度的。接口的设计粒度越小系统越灵活,这是事实,但是接口太多这也就使得结构复杂,维护难度大。因此实际中,怎样把握就靠开发的经验和常识了。
/*
* 接口隔离原则
*/
interface I
{
public function method1();
public function method2();
public function method3();
public function method4();
public function method5();
}
class A
{
public function depend1(I $i)
{
$i->method1();
}
public function depend2(I $i)
{
$i->method2();
}
public function depend3(I $i)
{
$i->method3();
}
}
class B implements I{
public function method1()
{
}
public function method2()
{
}
public function method3()
{
}
public function method4()
{
}
public function method5()
{
}
}
class C
{
public function depend1(I $i)
{
$i->method1();
}
public function depend2(I $i)
{
$i->method2();
}
public function depend3(I $i)
{
$i->method3();
}
}
class D implements I{
public function method1()
{
}
public function method2()
{
}
public function method3()
{
}
public function method4()
{
}
public function method5()
{
}
}
$a = new A();
$a->depend1(new B());
$a->depend2(new B());
$a->depend3(new B());
$c = new C();
$c->depend1(new D());
$c->depend2(new D());
$c->depend3(new D());
#------------------修正-------------------#
interface I1
{
public function method1();
}
interface I2
{
public function method2();
public function method3();
}
interface I3
{
public function method4();
public function method5();
}
class Al
{
public function depend1(I1 $i)
{
$i->method1();
}
public function depend2(I2 $i)
{
$i->method2();
}
public function depend3(I2 $i)
{
$i->method3();
}
}
class Bl implements I1, I2{
public function method1()
{
}
public function method2()
{
}
public function method3()
{
}
}
class Cl
{
public function depend1(I1 $i)
{
$i->method1();
}
public function depend2(I3 $i)
{
$i->method4();
}
public function depend3(I3 $i)
{
$i->method5();
}
}
class Dl implements I1, I3{
public function method1()
{
}
public function method4()
{
}
public function method5()
{
}
}
$a = new Al();
$a->depend1(new Bl());
$a->depend2(new Bl());
$a->depend3(new Bl());
$c = new Cl();
$c->depend1(new Dl());
$c->depend4(new Dl());
$c->depend5(new Dl());
Law of Demeter(最小知识原则):一个对象应该对其他对象有最少的了解。通俗来说就是,一个类对自己需要耦合或者调用的类知道的最少,你类内部怎么复杂,我不管,那是你的事,我只知道你有那么多公用的方法,我能调用。
迪米特原则不希望类与类之间建立直接的接触。如果真的需要有联系,那么就通过它们的友元类来传达。举例来说:你需要买房子了,现在存在三座合适的楼盘A,B,C,但是你不必直接去楼盘买楼,而是在售楼处去了解情况。这样就减少了你(购房者)与楼盘两个类之间耦合。
但是应用迪米特原则很可能会造成一个后果:系统会存在大量的中介类,这些类(如上面的售楼处类)之所以存在是为了传递类之间的相互调用关系,这就一定会程度上增加了系统的复杂度。
迪米特原则核心观念就是:类间解耦,弱耦合。
/*
* 迪米特原则(最少知道原则)
*/
class SubCompanyManager
{
public function getAllEmployee()
{
$arr = [];
for($i = 0; $i < 40; $i++) {
$arr[$i] = $i;
}
return $arr;
}
}
class CompanyManager
{
public function getAllEmployee(SubCompanyManager $sub)
{
for ($i = 0; $i < 30; $i++)
{
echo "总公司" . $i . "
";
}
$arr = $sub->getAllEployee();
foreach ($arr as $v) {
echo "分公司" . $v . "
";
}
}
}
$sub = new SubCompanyManager();
$class = new CompanyManager();
$class->getAllEmployee($sub);
#-------------------改正----------------------#
class SubCompanyManagerl
{
public function getAllEmployee()
{
for($i = 0; $i < 40; $i++) {
echo "分公司" . $i . "
";
}
}
}
class CompanyManagerl
{
public function getAllEmployee(SubCompanyManagerl $sub)
{
for ($i = 0; $i < 30; $i++)
{
echo "总公司" . $i . "
";
}
$sub->getAllEployee();
}
}
$subl = new SubCompanyManagerl();
$classl = new CompanyManagerl();
$classl->getAllEmployee($subl);
Open-Close Principle(OCP):一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。目的就是保证程序的扩展性好,易于维护和升级。
开闭原则被称为面向对象设计的基石,实际上,其他原则都可以看作是实现开闭原则的工具和手段。意思就是:软件对扩展应该是开放的,对修改是封闭的,通俗来说就是,开发一个软件时,应该对其进行功能扩展,而在进行这些扩展时,不需要对原来的程序进行修改。
好处是:软件可用性非常灵活,扩展性强。需要新的功能时,可以增加新的模块来满足新需求。另外由于原来的模块没有修改,所以不用担心稳定性的问题。
如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:瞳孔的个人网站