首页 > 其他分享 >IOC

IOC

时间:2022-10-17 21:55:58浏览次数:65  
标签:容器 Mother public mother IOC class

IOC

IOC的优劣势

容器革新

在java&php的开发过程中存在一个定律:使用对象之前,必须先创建,但是在Laravel&Spring框架中我们往往通过IOC容器直接获取,而无需事先创建它们,这种技术变革,就如同我们无需考虑对象的销毁一样,因为Java&Php的垃圾回收机制会帮我们进行处理。

优点

  • 自动依赖注入
  • 实现组件解耦
  • 提升程序的灵活性

缺点

  • 对象生成,步骤复杂
  • 使用反射生成对象,损耗运行效率

IOC的优势描述的太过于模糊和抽象,我们通过实现一个具体的需求,来进行了解

母亲通过故事书讲故事,哄孩子睡觉

原始实现
<?php

class Book{
    public function content()  : string{
        return "重生之我在FS写代码....";
    }
}

class Mother {
    private $book;

    public function __construct(Book $book) {
        $this->book = $book;
    }

    public function story() : string{
        return $this->book->content();
    }
}

class Son {
    private $mother;

    public function __construct(Mother $mother)
    {
        $this->mother = $mother;
    }

    public function sleep() {
        echo "听母亲讲" . $this->mother->storyTelling() . "慢慢入睡";
    }
}

$book = new Book();
$mother = new Mother($book);
$son = new Son($mother);
$son->sleep();
IOC实现
<?php

class Book{
    public function content()  : string{
        return "重生之我在FS写代码....";
    }
}
  
class Mother {
    private $book;

    public function __construct(Book $book) {
        $this->book = $book;
    }

    public function story() : string{
        return $this->book->content();
    }
}

class Son {
    private $mother;

    public function __construct(Mother $mother)
    {
        $this->mother = $mother;
    }

    public function sleep() {
        echo "听母亲讲" . $this->mother->story() . "慢慢入睡";
    }
}

Ioc::getInstance(Book::class);
Ioc::getInstance(Mother::class);
Ioc::make(Son::class,'sleep');

通过对比的方式,可以发现,在IOC实现中,我们不用在意类之间的依赖关系,只需将精力放置于业务上,容器会自动帮我们完成依赖注入

其余的两组优点我们可以通过下面的一组代码进行展示

需求:通过orderId 查询 order详情

//interface
<?php

namespace App\repository\interfaces;

interface OrderRepositoryInterface {
    function details(int $orderId) : string;
}

//repository
<?php

namespace App\repository;

use App\repository\interfaces\OrderRepositoryInterface;

class DatabaseOrderRepository implements OrderRepositoryInterface {

    function details(int $orderId): string
    {
        return "从数据库中获取订单数据";
    }
}

//service
<?php

namespace App\Service;

use App\repository\interfaces\OrderRepositoryInterface;

class OrderService {
    private $orderRepository;

    public function __construct(OrderRepositoryInterface $repository) {
        $this->orderRepository = $repository;
    }

    public function order(int $orderId): string
    {
        return $this->orderRepository->details($orderId);
    }
}

//provider
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\repository\RedisOrderRepository;
use App\repository\DatabaseOrderRepository;
use App\repository\interfaces\OrderRepositoryInterface;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
//        $this->app->bind(OrderRepositoryInterface::class,DatabaseOrderRepository::class);
        $this->app->bind(OrderRepositoryInterface::class,RedisOrderRepository::class);
    }
  
    public function boot()
    {
    }
}

上面的代码我们可以知道:OderService 与 OrderRepository组件彼此相互独立,实现了组件的解耦。同样当需求发生变更后,我们可以更换细节,来实现需求,提升程序的灵活性。

当然,IOC也不是全是优点,它依然也存在缺点。其中比较大的一个就是,IOC采用反射来创建对象,会导致性能有一定的损耗,但是相对于优点,这个缺点可以忽略不计,因为0.00几秒的损耗,不会对我们的程序有过多的影响。

IOC简介

IOC是Inversion of Control 的缩写,即控制反转

  • 上层模块不应该依赖下层模块,它们共同依赖一个抽象
  • 抽象不能依赖具体的实现,具体实现依赖于抽象

又称为依赖倒置原则(DIP),这是设计模式的六大原则之一

这些概念讲的太过于深奥,我们依然采用需求加代码来进行分析

需求一:母亲给孩子讲故事,只要给她一本书,她就可以按照书的内容给孩子讲故事

原始实现

public class LearnApplication {
    public static void main(String[] args) {
        Mother mother = new Mother();
        mother.story(new Book());
    }
}

class Book {
    public String getContent() {
        return "重生之在FS写代码.....";
    }
}

class Mother {
    public void story(Book book) {
        System.out.println("母亲开始讲故事了....");

        System.out.println(book.getContent());
    }
}

需求二:母亲给孩子讲故事,只要给她一份报纸,她就可以按照报纸的内容给孩子讲故事

当需求变更成报纸后,我们必须修改Mother类中的依赖项,才能让Mother拥有读报纸的能力。假如以后我们需求变更成杂志,网页等等,还需要不断的修改Mother类。显然这不是一个好的设计。原因就是:Mother与Book之间的耦合太高,必须降低它们之前耦合度才行。

DIP实现

public class MotherTwoApplication {
    public static void main(String[] args) {
        Mother mother = new Mother();
        mother.story(new Book());
    }
}

interface IReadr{
    String getContent();
}

class Book implements IReadr{
    @Override
    public String getContent() {
        return "书中:重生之在FS写代码.....";
    }
}

class News implements IReadr {
    @Override
    public String getContent() {
        return "报纸中:重生之在FS写代码.....";
    }
}

class Mother {
    public void story(IReadr readr) {
        System.out.println("母亲开始讲故事了....");

        System.out.println(readr.getContent());
    }
}

这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。这只是一个简单的例子,实际情况中,代表高层模块的Mother类将负责完成主要的业务逻辑,一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。

采用依赖倒置原则给多人并行开发带来了极大的便利,比如上例中,原本Mother类与Book类直接耦合时,Mother类必须等Book类编码完成后才可以进行编码,因为Mother类依赖于Book类。修改后的程序则可以同时开工,互不影响,因为Mother与Book类一点关系也没有。参与协作开发的人越多、项目越庞大,采用依赖导致原则的意义就越重大。

IOC的意义

Ioc不是什么技术,而是一种设计思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合,更优良的程序

传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了 IoC 容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

其实 IoC 对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在 IoC/DI 思想中,应用程序就变成被动的了,被动的等待 IoC 容器来创建并注入它所需要的资源了。

IoC 很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由 IoC 容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

IOC控制对象创建

  • laravel
class GoodController extends Controller
{
    public function good(int $goodId) {
        return app()->get(GoodService::class)->good($goodId);
    }
}
  • springboot
@GetMapping("/order/{orderId}")
public String order(@PathVariable("orderId") Integer orderId) {
  OrderService orderService = SpringUtil.getBean(OrderService.class);

  return orderService.order(orderId);
}

IOC和DI

其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以 2004 年大师级人物 Martin Fowler 又给出了一个新的名字:“依赖注入”,相对 IoC 而言,“依赖注入”明确描述了“被注入对象依赖 IoC 容器配置依赖对象”

深入理解IOC

如何理解IOC呢?理解IOC的关键是要明确“谁控制了谁,控制了什么,为何是反转(有反转就应该有正转)那些方面反转了。

  • 谁控制了谁?

    在以前,对象的创建和销毁都是由用户控制的,用了ioc之后,对象的创建和销毁就都交给容器来控制了,用户就不用管这些,只关注业务需求就好了。

img

  • 什么是反转?

    既然叫反转,肯定就有正转,正转其实就是对象去找实例,而反转就反过来了嘛,让实例来找对象;怎么找呢?当然是通过容器了。

img

  • 谁依赖谁?

    在spring项目中,将对象理解为Bean,也可以叫bean对象,这个bean和容器之间有个依赖关系,bean对象的创建是依赖容器的,就好像孩子依赖父母一样,孩子不能自己生出自己,需要父母的合作才能出生,这里的孩子就是bean,父母就是容器;

img

  • 谁注入谁?

    通过容器注入了bean对象,而且这个过程是自动化的,也就是说容器会自动找到和bean对象匹配的类型实例注入到对象中

img

模拟Spring IOC实现

模拟一个Spring容器

不管是使用SpringBoot,还是SpringMVC,还是直接使用Spring,都需要创建一个容器,也就是ApplicatikonContext对象

参考:DIP详讲

标签:容器,Mother,public,mother,IOC,class
From: https://www.cnblogs.com/ywjcqq/p/16800864.html

相关文章

  • IOC 生命周期-服务范围
    publicclassServicesPrpvoder:IServicesPrpvoder服务提供者可以利用IserviceScoprFactory创建一个服务范围IServiceScope对象IServicesScope的包含IServicesPrpvod......
  • 关于Spring的核心AOP和IOC理解
    spring概念轻量级的开源的J2EE框架。它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用,可以让我们的企......
  • winioctl.h(10326): [C4668] 没有将“_WIN32_WINNT_WIN10_TH2”定义为预处理器宏,用
    一般为Windows中的宏和UE4冲突所致在模块的xxx.Build.cs里面添加这个:bEnableUndefinedIdentifierWarnings=false;转自:https://blog.csdn.net/boonti/article/detail......
  • QFramework v1.0 使用指南 架构篇:18. 内置工具:IOCContainer
    QFramework架构的模块注册与获取是通过IOCContainer实现的。IOC的意思是控制反转,即控制反转容器。其技术的本质很简单,本质就是一个字典,Key是Type,Value是Object,即......
  • IOC校验
    varsc=newServiceCollection().AddScoped<IA,A>().AddSingleton<IB,B>().AddTransient<IC,C>().BuildServiceProvider(true);//ValidateScopes检查在scoped被......
  • IOC 根容器和子容器
         通过上图可知,容器中Transient的foo被每个容器创建,scoped的ber也在每个容器中创建,二单例的baz只在根容器中创建......
  • spring 的 IOC 和 AOP
    springjava企业开发框架spring全家桶web:springmvc、springflux持久层:redis、magnodb、springdata安全性:springsecurity脚手架:springboot微服务:springclo......
  • IOC 生命周期和释放
    使用ServiceCollection注入AddTransient,AddScoped,AddSingleton 三不同生命周期的的对象Transient最先释放Scope随后 Singleton 最后using(varsc=newServ......
  • 【SSM】学习笔记(一)—— Spring 概念、Spring IoC、Spring Bean相关知识、依赖注入、
    原视频:https://www.bilibili.com/video/BV1Fi4y1S7ix?p=1P1~P27目录一、Spring概述1.1、Spring家族1.2、Spring发展史1.3、SpringFramework系统架构图1.4、......
  • Spring 深入——IoC 容器 01
    IoC容器的实现学习——01目录IoC容器的实现学习——01简介IoC容器系列的设计与实现:BeanFactory和ApplicationContextBeanFactoryloadBeanDefinition()ApplicationConte......