큰 인터페이스 분할


9

데이터베이스에 액세스하기 위해 약 50 가지 방법으로 큰 인터페이스를 사용하고 있습니다. 인터페이스는 내 동료에 의해 작성되었습니다. 우리는 이것을 토론했다 :

나 : 50 가지 방법이 너무 많다. 코드 냄새입니다.
동료 : 어떻게해야합니까? DB 액세스를 원합니다.
나 : 네,하지만 미래에는 불분명하고 유지 보수가 거의 불가능합니다.
동료 : 네, 맞습니다. 좋지 않습니다. 그러면 인터페이스는 어떻게 보입니까?
나 : 각각 10 개의 메서드가있는 객체를 반환하는 5 개의 메서드는 어떻습니까?

흠,하지만 같지 않습니까? 이것이 정말로 더 명확 해 집니까? 노력할만한 가치가 있습니까?

때때로 나는 인터페이스를 원하는 상황에 처해 있으며 가장 먼저 떠오르는 것은 하나의 큰 인터페이스입니다. 이것에 대한 일반적인 디자인 패턴이 있습니까?


업데이트 (SJuan의 의견에 따라) :

"종류의 메소드": 데이터베이스에서 데이터를 가져 오기위한 인터페이스입니다. 모든 메소드의 형식은 (의사 코드)

List<Typename> createTablenameList()

메소드와 테이블은 정확히 1-1- 관계에 있지 않으며, 항상 데이터베이스에서 온 일종의 목록을 얻는다는 점이 더욱 강조됩니다.


12
관련 정보가 없습니다 (어떤 종류의 방법이 있는지). 어쨌든, 내 추측 : 당신이 숫자로만 나누면 동료가 옳다면 아무것도 개선하지 않을 것입니다. 하나의 가능한 구분 기준은 "엔티티"(거의 테이블과 동일)에 의해 반환 될 것입니다 (따라서 a UserDao와 a CustomerDao와 a ProductDao)
SJuan76

실제로 일부 테이블은 의미 상 "크릭"을 형성하는 다른 테이블에 가깝습니다. 방법도 마찬가지입니다.
TobiMcNamobi

코드를 볼 수 있습니까? 나는 그것이 4 세라는 것을 알고 당신은 아마 지금까지 고쳤을 것입니다 : D 그러나 나는이 문제에 대해 생각하고 싶습니다. 나는 전에 이와 같은 것을 해결했다.
clankill3r

@ clankill3r 실제로 위의 질문을 게시 한 특정 인터페이스에 더 이상 액세스 할 수 없습니다. 문제는 더 일반적입니다. 약 50 테이블과 각 테이블에 대한 DB를 상상하는 방법과 같은List<WeatherDataRecord> createWeatherDataTable() {db.open(); return db.select("*", "tbl_weatherData");}
TobiMcNamobi

답변:


16

예, 50 가지 방법은 코드 냄새이지만 코드 냄새는 자동으로 잘못되었다는 것이 아니라 다시 살펴 보는 것을 의미합니다. 해당 클래스를 사용하는 모든 클라이언트가 잠재적으로 50 개의 메소드를 모두 필요로하는 경우이를 분할하지 않아도됩니다. 그러나 이것은 가능하지 않습니다. 내 요점은 인터페이스를 임의로 분할하는 것이 전혀 분할하지 않는 것보다 나쁠 수 있다는 것입니다.

이를 고치는 단일 패턴은 없지만 원하는 상태를 설명하는 원칙Interface Segregation Principle (SOLID의 'I')이며, 클라이언트가 사용하지 않는 메소드에 의존해서는 안된다고 명시합니다 .

ISP 설명에서는이를 해결하는 방법에 대한 힌트를 제공합니다 . 클라이언트를보십시오 . 종종 클래스를 살펴보면 모든 것이 함께 속해있는 것처럼 보이지만 해당 클래스를 사용 하는 클라이언트 볼 때 명확한 구분이 나타납니다 . 인터페이스를 설계 할 때는 항상 클라이언트를 먼저 고려하십시오.

인터페이스를 분할해야하는지 여부를 결정하는 다른 방법은 두 번째 구현을 수행하는 것입니다. 종종 발생하는 것은 두 번째 구현에 많은 메소드가 필요하지 않으므로 분명히 자신의 인터페이스로 분리해야한다는 것입니다.


이것과 utnapistim의 대답은 정말 좋습니다.
TobiMcNamobi

13

동료 : 네, 맞습니다. 좋지 않습니다. 그러면 인터페이스는 어떻게 보입니까?

나 : 각각 10 개의 메서드가있는 객체를 반환하는 5 개의 메서드는 어떻습니까?

그것은 좋은 기준이 아닙니다 (실제로 그 진술에는 기준이 전혀 없습니다). 다음과 같이 그룹화 할 수 있습니다 (응용 프로그램이 금융 거래 앱이라고 가정).

  • 기능성 (삽입, 업데이트, 선택, 트랜잭션, 메타 데이터, 스키마 등)
  • 실체 (사용자 DAO , 예금 DAO 등)
  • 응용 분야 (금융 거래, 사용자 관리, 총계 등)
  • 추상화 수준 (모든 테이블 액세스 코드는 별도의 모듈입니다. 모든 선택 API는 자체 계층 구조에 있으며 트랜잭션 지원은 별도이며 모듈의 모든 변환 코드, 모듈의 모든 유효성 검사 코드 등)

흠,하지만 같지 않습니까? 이것이 정말로 더 명확 해 집니까? 노력할만한 가치가 있습니까?

올바른 기준을 선택하면 확실합니다. 당신이하지 않으면, 확실히하지 :).

몇 가지 예 :

  • ADODB는 객체 (귀하의 DB API는 아마 이미 제공) OO 프리미티브의 단순한 예를 들어

  • 추상화 수준이 높은 데이터 모델 아이디어 는 Django 데이터 모델 ( https://docs.djangoproject.com/en/dev/topics/db/models/ )을 참조하십시오 (C ++에서는 약간 더 많은 보일러 플레이트가 필요할 것입니다 코드,하지만 좋은 생각입니다). 이 구현은 MVC 디자인 패턴 내에서 "모델"역할을 염두에두고 설계되었습니다.

  • 기능적 기본 요소 (C API)만으로 구성된 간단한 API 아이디어 ( http://www.sqlite.org/c3ref/funclist.html ) 에 대한 sqlite API를 살펴보십시오 .


3

때때로 나는 인터페이스를 원하는 상황에 처해 있으며 가장 먼저 떠오르는 것은 하나의 큰 인터페이스입니다. 이것에 대한 일반적인 디자인 패턴이 있습니까?

모 놀리 식 클래스 라는 디자인 안티 패턴 입니다. 클래스 나 인터페이스에 50 개의 메소드가 있으면 SRP를 위반할 가능성이 있습니다. 모 놀리 식 수업은 모든 사람에게 모든 것이 되려고하기 때문에 생겨납니다.

DCI는 방법 팽창을 해결합니다. 기본적으로 클래스의 많은 책임은 특정 상황에서만 관련된 역할 (다른 클래스로 오프로드)에 할당 될 수 있습니다. 역할 적용은 믹스 인 또는 데코레이터를 포함한 여러 가지 방법으로 달성 할 수 있습니다 . 이 접근법은 수업을 집중하고 간결하게 유지합니다.

각각 10 개의 메서드가있는 객체를 반환하는 5 개의 메서드는 어떻습니까?

이것은 객체 자체가 인스턴스화 될 때 모든 역할을 인스턴스화하는 것을 제안합니다. 그러나 왜 필요하지 않은 역할을 인스턴스화합니까? 대신 실제로 필요한 상황에서 역할을 인스턴스화하십시오.

DCI에 대한 리팩토링이 명확하지 않다면 더 간단한 방문자 패턴을 사용할 수 있습니다. 유스 케이스 컨텍스트 작성을 강조하지 않고 유사한 이점을 제공합니다.

편집 : 이것에 대한 나의 생각은 약간 변경되었습니다. 나는 대안적인 답변을 제공했다.


1

그것은 다른 모든 대답에 요점이 빠져있는 것 같습니다. 요점은 인터페이스가 이상적으로 행동의 원자 덩어리를 정의해야한다는 것입니다. 이것이 SOLID의 I입니다.

수업에는 하나의 책임이 있어야하지만 여기에는 여전히 여러 가지 행동이 포함될 수 있습니다. 일반적인 데이터베이스 클라이언트 객체를 고수하기 위해 완전한 CRUD 기능을 제공 할 수 있습니다. 생성, 읽기, 업데이트 및 삭제의 네 가지 동작입니다. 순수한 SOLID 환경에서 데이터베이스 클라이언트는 IDatabaseClient가 아니라 ICreator, IReader, IUpdater 및 IDeleter를 구현하지 않습니다.

이것은 많은 이점이 있습니다. 첫째, 클래스 선언을 읽음으로써 클래스에 대해 많은 것을 즉시 배울 수 있습니다. 구현하는 인터페이스는 전체 이야기를 알려줍니다. 둘째, 클라이언트 객체를 인수로 전달해야하는 경우 이제 다른 유용한 옵션이 있습니다. IReader로 전달 될 수 있으며 수신자는 읽을 수만있을 것이라고 확신 할 수 있습니다. 다른 행동을 개별적으로 테스트 할 수 있습니다.

그러나 테스트와 관련하여 일반적인 방법은 전체 클래스 인터페이스의 일대일 복제 본인 클래스의 인터페이스를 때리는 것입니다. 테스트 만한다면 이것이 올바른 접근법 일 수 있습니다. 인형을 상당히 빨리 만들 수 있습니다. 그러나 그것은 거의 SOLID가 아니며 실제로 전용 목적으로 인터페이스를 남용합니다.

예, 50 가지 방법은 냄새이지만 나쁜 의도에 관계없이 의도와 목적에 따라 다릅니다. 확실히 이상적이지 않습니다.


0

데이터 액세스 계층에는 하나의 클래스에 많은 메소드가 첨부되는 경향이 있습니다. Entity Framework 또는 다른 ORM 도구를 사용해 본 적이 있다면 100 가지 방법이 생성되는 것을 볼 수 있습니다. 나는 당신과 당신의 동료가 수동으로 그것을 구현한다고 가정합니다. 코드 냄새가 필요하지 않지만 살펴보기에는 좋지 않습니다. 도메인을 모른다면 말하기가 어렵습니다.


방법이나 속성?
JeffO

0

FP와 OOP가 모두있는 모든 API에 거의 보편적으로 프로토콜을 사용합니다 (원하는 경우 인터페이스라고 부릅니다). (매트릭스를 기억해라? 결석이 없다!) 물론 구체적인 유형이 있지만 프로그램의 범위 내에서 모든 유형은 어떤 맥락에서 중요한 역할을하는 것으로 생각된다.

이것은 프로그램, 함수 등으로 전달 된 객체가 일련의 명명 된 동작을 가진 추상 엔티티로 생각 될 수 있음을 의미합니다. 객체는 일부 프로토콜 세트 역할을하는 것으로 생각할 수 있습니다. 사람 (콘크리트 유형)은 남자, 아버지, 남편, 친구 및 직원 일 수 있지만 엔티티를 두 개 이상의 합계로 간주하는 많은 기능을 상상할 수 없습니다.

복잡한 객체가 여러 가지 다른 프로토콜을 준수 할 가능성이 있지만 50 방법 API에 도달하기는 여전히 어려울 것입니다. 대부분의 프로토콜에는 1 또는 2 가지 방법이있을 수 있습니다. 50 가지 방법을 가진 모든 개체는 각자의 책임이있는 여러 개의 작은 구성 요소 집합으로 이루어져야합니다. 엔티티는 대체로 더 단순한 인터페이스를 제공하여 그 안에있는 API의 총계를 추상화합니다.

사물과 방법의 관점에서 생각하기보다는 추상화와 계약의 관점, 그리고 어떤 맥락에서 주제가 어떤 역할을하는지 생각하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.