본문 바로가기

PHP

[laravel]리포지토리 패턴 도입하기, 인터페이스 의존성 주입(DI)

1. 개요

애플리케이션 개발시 데이터는 다양한 위치에 저장합니다. RDB나 NoSQL 또는 캐시,파일 를 이용 하기도 합니다.

규모가 작거나 크지 않는 요구사항에는 필요없지만, 점차 요구사항이 많아지고 규모가 커지게 되면 확장성을 고려한 개발을 해야합니다. 

 

데이터 저장 위치가 바뀌더라도 프로그램은 가능한 변경되지 않도록 하는 것이 좋습니다.

이런 문제에대응한 방법의 하나로 리포지터리 패턴을 이용 할 수 있습니다.  

 

이전에 작성한 SOLID 중 OCP원칙을 지킬수 있습니다.

 

[JAVA] - [SPRING] 좋은 객체지향 설계의 5가지 원칙(SOLID)

 

[SPRING] 좋은 객체지향 설계의 5가지 원칙(SOLID)

클린코드로 유명한 로버트 마틴이 좋은 객체지향 설계의 5가지 원칙을 정리하였습니다. SOLID SRP: 단일 책임 원칙(Single Responsibilty Priciple) OCP: 개방-폐쇄 원칙(Open-Closed Priciple) LSP: 리스코프 치환 원

bakssse.tistory.com

 

리포지터리 패턴 적용 순서

기존에 비지니스 로직 클래스에서 직접 모든 데이터 조회, 조작 하는 것을 끊고, 구현체(리포지토리)에서 데이터 처리를 하고 인터페이스 의존성 주입(DI)을 통해, 보즈니스 로직에서는 데이터 스토어의 위치를 의식하지 않고 저장이나 검색을 할 수 있습니다.

2. 구현

다음 순서에 따라 구현을 진행 합니다. 

 

1. 인터페이스 작성

2. 엔티티 작성

3. 데이터베이스 조작을 담당하는 리포지토리 클래스 작성

4. Service 클래스에 구현체 대신 인터페이스 참조

5. 인터페이스와 구상 클래스 연결

 

1. 리포지터리 인터페이스

<?php

namespace App\DataProvider;
use App\Domain\Entity\Member;

interface MemberRepositoryInterface
{
    public function findByName(string $name): ?Member;
    public function store(Member $Member): int;
}

 

2.Entity 

<?php

namespace App\Domain\Entity;

class Member
{
    protected $id;
    protected $name;
    protected $address;

    public function __construct(?int $id, string $name, string $address)
    {
        $this->id = $id;
        $this->name = $name;
        $this->address = $address;
    }
    public function getName(): string
    {
        return $this->name;
    }

    public function getAddress(): string 
    {
        return $this->address;
    }
}

 

3.인터페이스 구현체 

<?php

namespace App\Domain\Repository;

use \App\DataProvider\MemberRepositoryInterface;
use \App\DataProvider\Eloquent\Member as EloquentMember;
use \App\Domain\Entity\Member;

class MemberRepository implements MemberRepositoryInterface
{
    private $eloquentMember;

    public function __construct(EloquentMember $eloquentMember) 
    {
        $this->eloqeuntMember = $eloquentMember;    
    }
    
    public function findByName(string $name): ?Publisher
    {

        $record = $this->eloquentMember->whereName($name)->first();
        if ($record === null) {
            return null;
        }
        return new Member(
            $record->id,
            $record->name,
            $record->address
        );
    }

    public function store(Member $Member): int
    {
        $eloqeunt = $this->eloqeuntMember->newInstance();
        $eloqeunt->name = $Member->getName();
        $eloqeunt->address = $Member->getAddress();
        $eloqeunt->save();

        return (int)$eloqeunt->id;
    }
    


}

 

4. 서비스 로직

<?php

namespace App\Services;
use App\DataProvider\MemberRepositoryInterface;
use App\Domain\Entity\Member;

class MemberService
{
    private $Member;

    /** 컨스트럭터 주입 */
    public function __construct(MemberRepositoryInterface $Member)
    {
        $this->Member = $Member;
    }

    /**
     * Member 존재 여부 확인
     * @param string $name
     * @return bool
     */
    public function exists(string $name): bool
    {
        // $count = Member::whereName($name)->count();
        // if ($count > 0) {

        if (!$this->Member->findByName($name)){
            return false;
        }
        return true;
    }

    /**
     * Member 등록
     * @param string $name
     * @param string $address
     * @return int
     */
    public function store(string $name, string $address)
    {
   
        return $this->Member->store(new Member(null, $name, $address));
        
    }

}

 

5.인터페이스와 구현체 바인드

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->bind(
          \App\DataProvider\MemberRepositoryInterface::class,
          \App\Domain\Repository\MemberRepository::class
        );
        
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        //
    }
}