Maison  >  Article  >  développement back-end  >  Quelles sont les trois caractéristiques majeures et les cinq principes majeurs de l'orientation objet ?

Quelles sont les trois caractéristiques majeures et les cinq principes majeurs de l'orientation objet ?

步履不停
步履不停original
2019-06-21 16:45:393316parcourir

Quelles sont les trois caractéristiques majeures et les cinq principes majeurs de l'orientation objet ?

Trois caractéristiques majeures de l'orienté objet

Encapsulation, héritage, polymorphisme

Qu'est-ce que l'encapsulation ?

Encapsulez des éléments objectifs dans des classes abstraites, et les classes ne peuvent permettre qu'à des classes ou des objets de confiance d'exploiter leurs données et méthodes, et masquer les informations des classes non fiables. Pour faire simple : l'encapsulation sépare le concepteur de l'objet de l'utilisateur de l'objet. L'utilisateur a seulement besoin de savoir ce que l'objet peut faire, et n'a pas besoin de savoir comment il est implémenté. L'encapsulation peut contribuer à améliorer la sécurité des classes et du système.

Qu'est-ce que l'héritage ?

L'héritage fait référence à la création d'une nouvelle classe dérivée qui hérite des données et des fonctions d'une ou plusieurs classes précédemment définies. Elle peut redéfinir ou ajouter de nouvelles données et fonctions, établissant ainsi un niveau ou une note.

Qu'est-ce que le polymorphisme ?

Le polymorphisme fait référence à : La même opération effectuée sur des instances de différentes classes produira des résultats d'exécution différents, c'est-à-dire que lorsque des objets de différentes classes recevront le même message, ils obtiendront des résultats différents.

Exemple de code

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());

Sortie :

Prenez le petit-déjeuner ! Taper!

Cinq principes de l'orientation objet

Principe de responsabilité unique, principe ouvert et fermé, principe de substitution de Liskov, principe d'inversion de dépendance, principe d'isolation d'interface

Quoi est le principe de responsabilité unique ?

Pour faire simple : une classe ne fait qu'une seule chose, n'implémentez pas trop de points fonctionnels pour la classe, et évitez de répartir les mêmes responsabilités entre les différentes classes. Si une classe a trop de responsabilités, il peut y avoir plus de raisons de changer, rendant le code plus couplé. Si les responsabilités sont mixtes et peu claires, cela rendra le code difficile à maintenir et affectera l’ensemble de l’organisme.

Par exemple : modèle d'usine. La raison pour laquelle le modèle d'usine est appelé modèle d'usine est qu'il est responsable de la "production" des objets.

Exemple de code

Avantages du modèle d'usine : un objet est nouveau à plusieurs endroits. Lorsque ces noms changent, il n'est pas nécessaire de les modifier un par un, un seul endroit doit l'être. modifié.

<?php
class MyObject
{
    public function __construct()
    {
        echo "test code";
    }
}

//工厂类
class MyFactory
{
    public static function factory()
    {
        return new MyObject();
   }
}

$instance = MyFactory::factory();//test code

Quel est le principe ouvert-fermé ?

Principe ouvert et fermé : Une classe est extensible mais ne peut pas être modifiée. En d’autres termes, il est ouvert à l’extension et fermé à la modification.

1. Ouvert à l'expansion signifie que lorsqu'il y a de nouveaux besoins ou changements, le code existant peut être étendu pour s'adapter à de nouvelles situations.

2. Il est fermé aux modifications. Lors de l'extension des fonctions du module, les modules du programme existants ne doivent pas être affectés.

Le point clé pour réaliser le principe d'ouverture et de fermeture : la programmation abstraite, plutôt que la programmation concrète, car l'abstraction est relativement stable et rend les classes dépendantes de classes et d'interfaces abstraites fixes, donc les modifications sont fermées. En ce qui concerne les mécanismes d'héritage et de polymorphisme orientés objet, vous pouvez hériter de classes abstraites ou implémenter des interfaces, et vous pouvez réécrire leurs méthodes pour modifier le comportement inhérent et implémenter de nouvelles extensions de méthodes, donc c'est ouvert.

Par exemple : Le mode Décorateur (Decorator) peut ajouter et modifier dynamiquement les fonctionnalités d'une classe. Une classe fournit une fonction. Si vous souhaitez modifier et ajouter des fonctions supplémentaires, en mode de programmation traditionnel, vous devez écrire une sous-classe pour en hériter et réimplémenter la méthode de classe. En mode décorateur, il vous suffit de l'ajouter au moment de l'exécution. . Ceci peut être implémenté avec un seul objet décorateur, permettant une flexibilité maximale.

<?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=&#39;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=&#39;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();

Qu'est-ce que le principe de substitution de Richter ?

Parce que l'héritage dans la technologie de programmation orientée objet est trop simple dans une programmation spécifique, dans la conception et la mise en œuvre de la programmation de nombreux systèmes, nous ne réfléchissons pas sérieusement et rationnellement aux relations entre les différentes classes de l'application. système. Si la relation d'héritage est appropriée et si la classe dérivée peut correctement remplacer certaines méthodes de la classe de base. Par conséquent, des abus d'héritage ou des héritages erronés se produisent souvent, ce qui entraîne beaucoup de problèmes lors de la maintenance ultérieure du système.

Idée de base : les sous-classes doivent pouvoir remplacer leurs classes parentes. Cette idée est incarnée dans la spécification des contraintes du mécanisme d'héritage.Ce n'est que lorsque la sous-classe peut remplacer la classe parent que le système peut reconnaître la sous-classe pendant l'exécution.C'est la base pour garantir la réutilisation de l'héritage.

<?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;
    }
}

Le principe de substitution de Liskov est une contrainte sur l'héritage de classe. Il existe deux interprétations du principe de substitution de Liskov :

1 Vous ne pouvez pas simplement hériter de classes inappropriées avec des méthodes ou des attributs redondants (Exemple 1).

2. Les sous-classes peuvent étendre les fonctions de la classe parent, mais ne peuvent pas modifier les fonctions d'origine de la classe parent (Exemple 2).

Le principe de substitution de Liskov contient les significations cachées suivantes :

1. Les sous-classes peuvent implémenter les méthodes abstraites de la classe parent, mais ne peuvent pas remplacer les méthodes non abstraites de la classe parent.

2. Les sous-classes peuvent ajouter leurs propres méthodes uniques.

3. Lorsqu'une méthode d'une sous-classe remplace une méthode d'une classe parent, les conditions préalables de la méthode (c'est-à-dire les paramètres formels de la méthode) sont plus souples que les paramètres d'entrée de la méthode de la classe parent.

4. Lorsqu'une méthode d'une sous-classe implémente une méthode abstraite d'une classe parent, les postconditions de la méthode (c'est-à-dire la valeur de retour de la méthode) sont plus strictes que celles de la classe parent.

Qu'est-ce que le principe d'inversion de dépendance ?

Pour faire simple : une classe ne doit pas être obligée de dépendre d'une autre classe. Chaque classe est remplaçable par une autre classe.

Concepts spécifiques :

1. Le module supérieur ne doit pas dépendre du module inférieur, ils dépendent tous d'une abstraction (la classe parent ne peut pas dépendre de la sous-classe, ils dépendent tous du résumé classe).

2.抽象不能依赖于具体,具体应该依赖于抽象。

为什么要依赖接口?因为接口体现对问题的抽象,同时由于抽象一般是相对稳定的或者是相对变化不频繁的,而具体是易变的。因此,依赖抽象是实现代码扩展和运行期内绑定(多态)的基础:只要实现了该抽象类的子类,都可以被类的使用者使用。

<?php

interface employee
{
    public function working();
}

class teacher implements employee//具体应该依赖与抽象
{
    public function working(){
        echo &#39;teaching...&#39;;
    }
}

class coder implements employee
{
    public function working(){
        echo &#39;coding...&#39;;
    }
}

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)的概念:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。

结语

实践出真理

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn