What is encapsulation?
Encapsulate objective things into abstract classes, and classes can only allow trusted classes or objects to operate their data and methods, and hide information from untrusted classes. To put it simply: encapsulation separates the designer of the object from the user of the object. The user only needs to know what the object can do, and does not need to know how it is implemented. Encapsulation can help improve class and system security.
What is inheritance?
Inheritance refers to creating a new derived class that inherits data and functions from one or more previously defined classes. It can redefine or add new data and functions, thus establishing a class. level or grade.
What is polymorphism?
Polymorphism refers to: The same operation performed on instances of different classes will produce different execution results, that is, when objects of different classes receive the same message, they will get different results.
class eat { public function breakfast() { echo "吃早饭!"; } } class typist { public function type() { echo "打字!"; } } function printWorking($obj) { if ($obj instanceof eat) { echo $obj->breakfast(); } elseif ($obj instanceof typist) { echo $obj->type(); } else { echo "error"; } } printWorking(new eat()); echo PHP_EOL; printWorking(new typist());
Output:
Eat breakfast! Typing!
Single responsibility principle, open and closed principle, Richter substitution principle, dependency inversion principle, interface isolation principle
What is Single responsibility principle?
To put it simply: a class only does one thing, do not implement too many functional points for the class, and avoid spreading the same responsibilities to different classes. If a class has too many responsibilities, there may be more reasons for changes, making the code more coupled. If the responsibilities are mixed and unclear, the code will be difficult to maintain, which will affect the whole body.
For example: Factory pattern. The reason why the factory pattern is called the factory pattern is because it is responsible for "producing" objects.
Benefits of the factory pattern: An object is new in multiple places. When such names change, there is no need to modify them one by one, only one place needs to be modified.
<?php class MyObject { public function __construct() { echo "test code"; } } //工厂类 class MyFactory { public static function factory() { return new MyObject(); } } $instance = MyFactory::factory();//test code
What is the open-closed principle?
Open and closed principle: A class is extensible but cannot be modified. In other words, it is open to extension and closed to modification.
1. Open for extension means that when there are new needs or changes, the existing code can be extended to adapt to the new situation.
2. It is closed to modifications. When extending module functions, existing program modules should not be affected.
The key point in realizing the open and closed principle: abstract programming, rather than concrete programming, because abstraction is relatively stable and makes classes dependent on fixed abstract classes and interfaces, so modifications are closed. As for the object-oriented inheritance and polymorphism mechanisms, you can inherit abstract classes or implement interfaces, and you can rewrite their methods to change the inherent behavior and implement new extensions of the methods, so it is open.
For example: Decorator mode (Decorator) can dynamically add and modify the functionality of a class. A class provides a function. If you want to modify and add additional functions, in the traditional programming mode, you need to write a subclass to inherit it and reimplement the class method. Using the decorator mode, you only need to add it at runtime. This can be implemented with a single decorator object, allowing for maximum flexibility.
<?php /** * 输出一个字符串 * 装饰器动态添加功能 * Class EchoText */ class EchoText { protected $decorator = []; public function Index() { //调用装饰器前置操作 $this->beforeEcho(); echo "你好,我是装饰器。"; //调用装饰器后置操作 $this->afterEcho(); } //增加装饰器 public function addDecorator(Decorator $decorator) { $this->decorator[] = $decorator; } //执行装饰器前置操作 先进先出原则 protected function beforeEcho() { foreach ($this->decorator as $decorator) $decorator->before(); } //执行装饰器后置操作 先进后出原则 protected function afterEcho() { $tmp = array_reverse($this->decorator); foreach ($tmp as $decorator) $decorator->after(); } } /** * 装饰器接口 * Class Decorator */ interface Decorator { public function before(); public function after(); } /** * 颜色装饰器实现 * Class ColorDecorator */ class ColorDecorator implements Decorator { protected $color; public function __construct($color) { $this->color = $color; } public function before() { echo "<dis style='color: {$this->color}'>"; } public function after() { echo "</div>"; } } /** * 字体大小装饰器实现 * Class SizeDecorator */ class SizeDecorator implements Decorator { protected $size; public function __construct($size) { $this->size = $size; } public function before() { echo "<dis style='font-size: {$this->size}px'>**"; } public function after() { echo "</div>"; } } //实例化输出类 $echo = new EchoText(); //增加装饰器 $echo->addDecorator(new ColorDecorator('red')); //增加装饰器 $echo->addDecorator(new SizeDecorator('22')); //输出 $echo->Index();
What is the Richter substitution principle?
Because inheritance in object-oriented programming technology is too simple in specific programming, in the design and programming implementation of many systems, we do not seriously and rationally think about the relationships between various classes in the application system. Whether the inheritance relationship is appropriate and whether the derived class can correctly override certain methods in the base class. Therefore, abuse of inheritance or wrong inheritance often occurs, which brings a lot of trouble to the later maintenance of the system.
Core idea: Subclasses must be able to replace their parent classes. This idea is embodied in the constraint specification of the inheritance mechanism. Only when the subclass can replace the parent class can the system recognize the subclass during runtime. This is the basis for ensuring inheritance reuse.
<?php //例子1 class Bird{ protect function fly(){ } } //翠鸟 class KingFisher extends Bird{ } //鸵鸟 class Ostrich extends Bird{ //鸵鸟不会飞啊 } //例子2 class A{ protect function add($a, $b){ return $a + $b; } } //重载 class B extends A{ protected function add($a, $b){ return $a + $b + 100; } }
The Liskov substitution principle is a constraint on class inheritance. There are two understandings of the Liskov substitution principle:
1. You cannot just inherit inappropriate classes with redundant methods or attributes (Example 1).
2. A subclass can extend the functions of the parent class, but cannot change the original functions of the parent class (Example 2).
The Liskov substitution principle contains the following hidden meanings:
1. Subclasses can implement abstract methods of the parent class, but cannot override non-abstract methods of the parent class.
2. Subclasses can add their own unique methods.
3. When a method of a subclass overrides a method of a parent class, the preconditions of the method (that is, the formal parameters of the method) are looser than the input parameters of the parent class method.
4. When a method of a subclass implements an abstract method of a parent class, the postconditions of the method (i.e., the return value of the method) are more stringent than those of the parent class.
What is the dependency inversion principle?
To put it simply: a class should not be forced to depend on another class. Each class is replaceable for another class.
Specific concepts:
1. The upper module should not depend on the lower module. They all depend on an abstraction (the parent class cannot depend on the subclass, they all depend on the abstract class).
2.抽象不能依赖于具体,具体应该依赖于抽象。
为什么要依赖接口?因为接口体现对问题的抽象,同时由于抽象一般是相对稳定的或者是相对变化不频繁的,而具体是易变的。因此,依赖抽象是实现代码扩展和运行期内绑定(多态)的基础:只要实现了该抽象类的子类,都可以被类的使用者使用。
<?php interface employee { public function working(); } class teacher implements employee//具体应该依赖与抽象 { public function working(){ echo 'teaching...'; } } class coder implements employee { public function working(){ echo 'coding...'; } } class workA//例子1 { public function work(){ $teacher = new teacher; $teacher->working(); } } class workB//例子2 { private $e; public function set(employee $e){ $this->e = $e; } public function work(){ $this->e->working(); } } $worka = new workA;//workA 依赖于 teacher 类 不符合依赖倒置原则 $worka->work(); $workb = new workB;//workB 不依赖与某个类 既可以注入 teacher 也可以 注入 coder $workb->set(new teacher()); $workb->work();
在workA(例子1)中,work方法依赖于teacher实现;在workB(例子2)中,work转而依赖抽象,这样可以把需要的对象通过参数传入。上述代码通过接口,实现了一定程度的解耦,但仍然是有限的。不仅是使用接口,使用工厂等也能实现一定程度的解耦和依赖倒置。
在workB中,teacher实例通过set方法传入,从而实现了工厂模式。由于这样的实现仍然是硬编码的,为了实现代码的进一步扩展,把这个依赖关系写在配置文件里,指明workB需要一个teacher对象,专门由一个程序配置是否正确(如所依赖的类文件是否存在)以及加载配置中所依赖的实现,这个检测程序,就称为IOC容器(这里不清楚IOC的小伙伴可以自行谷歌)。
什么是接口隔离原则?
其核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口(只需要关心接口,不需要关心实现)。
接口隔离原则体现在:
1.接口应该是内聚的,应该避免 “胖” 接口。
2.不要强迫依赖不用的方法,这是一种接口污染。
3.表明客户端不应该被强迫实现一些不会使用的接口,应该把胖接口分组,用多个接口代替它,每个接口服务于一个子模块。简单地说,就是使用多个专门的接口比使用单个接口要好很多。
隔离的手段主要有以下两种:
1、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销(设计模式中,如:代理模式,策略模式中都用到了委托的概念,好奇的小伙伴可以自行谷歌,这里就不贴代码了)。
2、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。
胖接口的实例说明
<?php interface Animal{ public function walk(); public function speak(); } //实现狗的一个接口 class Dog implements Animal{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; } } //ok,现在我们想创建一个鱼类,它会游泳,怎么办呢? //我们必须要修改接口,还会影响到dog类的实现,而fish也需要实现walk和speak方法,如下代码所示: interface Animal{ public function walk(); public function speak(); public function swim(); } //修改后的Gog类 class Dog implements Animal{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; } public function swim(){ } } //鱼类 class Fish implements Animal{ public function walk(){ } public function speak(){ } public function swim(){ echo "fish can swim"; } }
这时Animal接口类就呈现出了”胖“接口的特征了。所谓胖接口其实就是接口中定义了不是所有实现类都需要的方法,就像Animal接口类,有些动物是不会游泳的,有些动物是不会行走的,还有些动物是不会飞的。如果将这些方法都写在一个Animal接口类中,那么后期的扩展和维护简直就是一场灾难。
那么,怎么解决以上问题呢?
很简单,接口细化即可,将Animal接口类拆分成三个接口类,然后用多继承分离接口就ok了。
<?php interface animalCanSpeak{ public function speak(); } interface AnimalCanSwim{ public function swim(); } interface animalCanSpeak{ public function speak(); } //定义好这几个接口类之后,dog和fish的实现就容易多了 //狗类 class Dog implements animalCanSpeak,animalCanWalk{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; } } //鱼类 class Fish implements AnimalCanSwim{ public function swim(){ echo "fish can swim"; } }
接口隔离原则(Interface Segregation Principle, ISP)的概念:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。
实践出真理
The above is the detailed content of What are the three major characteristics and five major principles of object-oriented. For more information, please follow other related articles on the PHP Chinese website!