ホームページ  >  記事  >  バックエンド開発  >  オブジェクト指向の3大特徴と5大原則とは

オブジェクト指向の3大特徴と5大原則とは

步履不停
步履不停オリジナル
2019-06-21 16:45:393319ブラウズ

オブジェクト指向の3大特徴と5大原則とは

オブジェクト指向の 3 つの主要な特徴

カプセル化、継承、ポリモーフィズム

カプセル化とは何ですか?

客観的なものを抽象クラスにカプセル化すると、クラスは信頼できるクラスまたはオブジェクトにのみデータとメソッドの操作を許可し、信頼できないクラスからは情報を隠すことができます。簡単に言うと、カプセル化により、オブジェクトの設計者とオブジェクトのユーザーが分離され、ユーザーはオブジェクトで何ができるかを知る必要があるだけで、オブジェクトがどのように実装されるかを知る必要はありません。カプセル化は、クラスとシステムのセキュリティを向上させるのに役立ちます。

継承とは何ですか?

継承とは、以前に定義された 1 つ以上のクラスからデータと関数を継承する新しい派生クラスを作成することを指します。新しいデータと関数を再定義または追加することで、クラスのレベルまたはグレードを確立できます。

ポリモーフィズムとは何ですか?

ポリモーフィズムとは、異なるクラスのインスタンスに対して同じ操作を実行すると、異なる実行結果が生成されます。つまり、異なるクラスのオブジェクトが同じメッセージを受信すると、異なる結果が得られます。

コード例

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

出力:

朝食を食べてください!タイピング!

オブジェクト指向の 5 つの原則

単一責任原則、オープンおよびクローズド原則、リヒター置換原則、依存関係逆転原則、インターフェース分離原則

何単一責任原則とは何ですか?

簡単に言うと、クラスは 1 つのことだけを行い、クラスにあまりにも多くの機能ポイントを実装しないでください。また、同じ責任を異なるクラスに分散させないでください。クラスの責任が多すぎる場合、変更の理由がさらに多くなり、コードがより結合されたものになる可能性があります。責任が混在していて不明確な場合、コードの保守が困難になり、全体に影響を及ぼします。

例: ファクトリ パターン ファクトリ パターンがファクトリ パターンと呼ばれる理由は、オブジェクトを「生成」する役割を担うためです。

コード例

ファクトリ パターンの利点: オブジェクトは複数の場所で新しくなります。そのような名前が変更された場合、それらを 1 つずつ変更する必要はなく、1 か所だけを変更する必要があります。変更されました。

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

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

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

オープンクローズ原則とは何ですか?

オープンとクローズの原則: クラスは拡張可能ですが、変更することはできません。言い換えれば、拡張にはオープンであり、変更にはクローズドです。

1. 拡張にオープンとは、新しいニーズや変更が生じたときに、既存のコードを拡張して新しい状況に適応できることを意味します。

2. モジュールの機能を拡張する場合、既存のプログラム モジュールに影響を与えることはできません。

オープンとクローズの原則を実現するための重要なポイント: 具象プログラミングではなく抽象プログラミング。抽象化は比較的安定しており、クラスが固定の抽象クラスとインターフェイスに依存するため、変更はクローズされます。オブジェクト指向の継承とポリモーフィズムのメカニズムに関しては、抽象クラスを継承したりインターフェイスを実装したり、そのメソッドを書き換えて固有の動作を変更したり、メソッドの新しい拡張を実装したりできるため、オープンです。

例: デコレータ モード (デコレータ) では、クラスの機能を動的に追加および変更できます。クラスは関数を提供します。関数を変更して追加する場合、従来のプログラミング モードでは、サブクラスを作成してそれを継承し、クラス メソッドを再実装する必要があります。デコレータ モードを使用すると、実行時に関数を追加するだけで済みます。これは単一のデコレータ オブジェクトで実装できるため、最大限の柔軟性が得られます。

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

リヒター置換原理とは何ですか?

オブジェクト指向プログラミング技術における継承は、特定のプログラミングでは単純すぎるため、多くのシステムの設計およびプログラミング実装では、アプリケーション内のさまざまなクラス間の関係について真剣かつ合理的に考えられていません。継承関係が適切かどうか、および派生クラスが基本クラスの特定のメソッドを正しくオーバーライドできるかどうか。そのため、相続の濫用や不正相続が多発し、その後の制度維持に多大な支障をきたすことになる。

中心的な考え方: サブクラスは親クラスを置き換えることができる必要があります。この考え方は、継承メカニズムの制約仕様に具体化されており、サブクラスが親クラスを置き換えることができる場合にのみ、システムは実行時にサブクラスを認識できます。これが、継承を確実に再利用するための基礎となります。

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

リスコフ置換原則は、クラス継承に対する制約です。 Liskov 置換原則には 2 つの理解があります:

1. 冗長なメソッドまたは属性を持つ不適切なクラスを単純に継承することはできません (例 1)。

2. サブクラスは親クラスの機能を拡張できますが、親クラスの元の機能を変更することはできません (例 2)。

Liskov 置換原則には次の隠された意味が含まれています:

1. サブクラスは親クラスの抽象メソッドを実装できますが、親クラスの非抽象メソッドをオーバーライドすることはできません。

2. サブクラスは独自の一意のメソッドを追加できます。

3. サブクラスのメソッドが親クラスのメソッドをオーバーライドする場合、メソッドの前提条件 (つまり、メソッドの仮パラメータ) は、親クラスのメソッドの入力パラメータよりも緩くなります。

4. サブクラスのメソッドが親クラスの抽象メソッドを実装する場合、メソッドの事後条件 (メソッドの戻り値) は親クラスの事後条件よりも厳しくなります。

依存関係逆転の原理とは何ですか?

簡単に言えば、クラスは別のクラスに依存することを強制されるべきではなく、各クラスは別のクラスに置き換え可能です。

具体的な概念:

1. 上位モジュールは下位モジュールに依存すべきではありません。それらはすべて抽象化に依存します (親クラスはサブクラスに依存できません。それらはすべて抽象化に依存します)。クラス)。

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

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

结语

实践出真理

以上がオブジェクト指向の3大特徴と5大原則とはの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。