솔리드 (SOLID) 및 기타 디자인 원칙에 대해 읽었습니다. 나는 ISP가 "프로그램이 아닌 인터페이스에 대한 구현"이라고 생각했다. 그러나 이것들이 다른 원리 인 것처럼 보입니까?인터페이스 분리 원칙 - 인터페이스에 대한 프로그램
차이가 있습니까?
솔리드 (SOLID) 및 기타 디자인 원칙에 대해 읽었습니다. 나는 ISP가 "프로그램이 아닌 인터페이스에 대한 구현"이라고 생각했다. 그러나 이것들이 다른 원리 인 것처럼 보입니까?인터페이스 분리 원칙 - 인터페이스에 대한 프로그램
차이가 있습니까?
ISP는 하나의 개별적이고 응집력있는 행동을 나타내는 각 인터페이스의 개념에 중점을 둡니다.
즉, 개체가 수행해야하는 논리적 인 각 그룹은 단일 특정 인터페이스에 매핑됩니다. 클래스는 여러 가지 작업을 수행하려고 할 수 있지만 각 작업은 해당 동작을 나타내는 특정 인터페이스에 매핑됩니다. 아이디어는 각 인터페이스가 매우 집중되어 있습니다.
로버트 마틴 (Robert Martin)은 "Java 프로그래머 용 UML"이라는 책에서 인터페이스 분리 원리 (Interface Separation Principle, ISP)에 대해 매우 잘 설명하고 있습니다. 이를 바탕으로, 나는 ISP가 하나의 논리적이고 일관된 일들에 초점을 맞추고 있다고 생각하지 않는다. 왜냐하면, 그것은 말도하지 않습니다. 또는, 적어도 그것은 말없이 가야한다. 각 클래스, 인터페이스 또는 추상 클래스는 그렇게 설계되어야합니다.
ISP는 무엇입니까? 예를 들어 설명해 드리겠습니다. 클래스 A는 클래스 A의 클라이언트이고 클래스 B는 클래스 A의 클라이언트입니다. 클래스 A에는 10 개의 메소드가 있으며 그 중 두 개만 B에서 사용합니다. 이제 B는 A의 10 가지 메소드 모두에 대해 알아야합니다. ? 아마 정보 숨기기의 원칙이 아닙니다. 더 많이 노출할수록 더 많은 커플 링 기회를 창출 할 수 있습니다. 따라서 두 클래스 (분리) 사이에 인터페이스를 삽입 할 수 있습니다 (C).
class A {
method1()
method2()
// more methods
method10()
}
class B {
A a = new A()
}
가 될 것이며,이 인터페이스는 단지 B에 의해 사용되는 두 가지 방법을 선언하는 것이고, B는 이제
A.
직접 대신, 그 인터페이스에 의존 할 것이다interface C {
method1()
method2()
}
class A implements C{
method1()
method2()
// more methods
method10()
}
class B {
C c = new A()
}
이것은 B가해야하는 것 이상을 알 수 없도록합니다.
자세한 설명을 위해 시간을내어 +1하십시오! – hangar18
우수 답변! –
@ Pete Stensønes 설명은 내가 한 것보다 더 일반적이고 정확합니다. 나는 그의 정의에 더 많은 관심을 기울일 것을 사람들에게 제안한다. 내 잘못은 아니지만 그 개념을 한 가지 유스 케이스로 설명하며 일반적인 포인트를 놓치고 있습니다. –
위의 두 대답 모두에 동의하십시오. 여기에 (PHP에서)이 원칙의 실제 예입니다
@Override
public void foo() {
//Not used: just needed to implement interface
}
특히 컬렉션에서만 NotImplementedException을 throw하는 Java API 클래스와 비교하십시오. Moderation에서는 인터페이스에서 부분적으로 사용되는 메소드에 유용 할 수 있지만 MutableMap을 사용하여 Map을 확장하는 것이 대안 일 수 있습니다. – hexafraction
을
문제 : 그냥, 당신은 자신이 일을 찾을해야 위의 TrueWill의 코드 냄새의 예를 제공합니다 성명서 :
다양한 형태의 콘텐츠에 의견/토론이 필요합니다. 이 내용은 포럼 주제에서 뉴스 기사, 사용자 프로필, 대화 형식의 개인 메시지에 이르기까지 다양합니다.
우리는 주어진 콘텐츠 엔티티에 Discussion
를 첨부 재사용 가능한 DiscussionManager
클래스를 원할 것입니다
아키텍처. 그러나 위의 네 가지 예 (및 그 이상)는 개념적으로 모두 다릅니다. 만약 우리가 DiscussionManager
에서 그것들을 사용하기를 원한다면, 네 + 모든 것이 모두 공유하는 하나의 공용 인터페이스를 가질 필요가 있습니다. 인수가 누출되지 않도록하려는 경우 (예 : 유형 확인 없음)를 제외하고는 DiscussionManager
에서 사용할 수있는 다른 방법은 없습니다.
해결 방법 : 이러한 방법으로 Discussable
인터페이스 :
attachDiscussion($topic_id)
detachDiscussion()
getDiscussionID()
다음 DiscussionManager
은 다음과 같습니다
class DiscussionManager
{
public function addDiscussionToContent(Discussable $Content)
{
$Discussion = $this->DiscussionFactory->make(...some data...);
$Discussion->save() // Or $this->DiscussionRepository->save($Discussion);
$Content->attachDiscussion($Discussion->getID()); // Maybe saves itself, or you can save through a repository
}
public function deleteDiscussion(Discussable $Content)
{
$id = $Content->getDiscussionID();
$Content->detatchDiscussion();
$this->DiscussionRepository->delete($id);
}
public function closeDiscussion($discussion_id) { ... }
}
이렇게하면 DiscussionManager
은 사용하는 다양한 콘텐츠 형식과 관련이없는 동작을 전혀 신경 쓰지 않습니다. 그것은 오직 그 행동이 관련된 것과 관계없이 그들이 필요로하는 행동에만 관심이 있습니다. 따라서 토론 할 내용 유형 인 Discussable
인터페이스를 제공하여 인터페이스 분리 원리를 사용하고 있습니다.
이것은 추상 기본 클래스가 좋은 생각이 아닌 상황의 좋은 예입니다. 포럼 주제, 사용자 프로필 및 뉴스 기사는 원격 개념적으로 똑같은 것이 아니기 때문에 토론 행동을 상속 받도록하려고하면 관련없는 부모와 이상하게 연결됩니다. 토론을 나타내는 특정 인터페이스를 사용하여 토론하려는 엔티티가 해당 토론을 관리 할 클라이언트 코드와 호환되는지 확인할 수 있습니다.
이 예제는 PHP의 특성을 사용하기에 좋은 후보가 될 수 있습니다.
구현할 많은 메소드가있는 하나의 뚱뚱한 인터페이스가 있다고 가정하십시오.
뚱뚱한 공용 영역을 실행하는 어떤 종류는이 모든 방법을위한 실시를 제공해야한다. 일부 방법은 해당 구체적인 클래스에 적용되지 않을 수 있습니다. 그러나 여전히 인터페이스 분리 원칙이없는 구현을 제공해야합니다.
에 예제 코드를 살펴보고 Interface segregation이 없음.
interface Shape{
public int getLength();
public int getWidth();
public int getRadius();
public double getArea();
}
class Rectangle implements Shape{
int length;
int width;
public Rectangle(int length, int width){
this.length = length;
this.width = width;
}
public int getLength(){
return length;
}
public int getWidth(){
return width;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return width * length;
}
}
class Square implements Shape{
int length;
public Square(int length){
this.length = length;
}
public int getLength(){
return length;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return length * length;
}
}
class Circle implements Shape{
int radius;
public Circle(int radius){
this.radius = radius;
}
public int getLength(){
// Not applicable
return 0;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
return radius;
}
public double getArea(){
return 3.14* radius * radius;
}
}
public class InterfaceNoSeggration{
public static void main(String args[]){
Rectangle r = new Rectangle(10,20);
Square s = new Square(15);
Circle c = new Circle(2);
System.out.println("Rectangle area:"+r.getArea());
System.out.println("Square area:"+s.getArea());
System.out.println("Circle area:"+c.getArea());
}
}
출력 :
java InterfaceNoSeggration
Rectangle area:200.0
Square area:225.0
Circle area:12.56
주 :
Shape
는 Rectangle
, Circle
및 Square
같은 모든 Shape
구현에 필요한 방법을 포함하는 범용 지방 인터페이스입니다. 그러나 일부 방법은 각각의 모양에 필요한 분리의 부재에서
Rectangle : getLength(), getWidth(), getArea()
Square : getLength() and getArea()
Circle : getRadius() and getArea()
차일, 모든 모양은 전체 지방 인터페이스를 구현 한 : 모양. 우리는 다음과 같은 코드를 변경하는 경우
우리는 인터페이스 분리의 원칙과 같은 결과를 얻을 수 있습니다.
interface Length{
public int getLength();
}
interface Width{
public int getWidth();
}
interface Radius{
public int getRadius();
}
interface Area {
public double getArea();
}
class Rectangle implements Length,Width,Area{
int length;
int width;
public Rectangle(int length, int width){
this.length = length;
this.width = width;
}
public int getLength(){
return length;
}
public int getWidth(){
return width;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return width * length;
}
}
class Square implements Length,Area{
int length;
public Square(int length){
this.length = length;
}
public int getLength(){
return length;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return length * length;
}
}
class Circle implements Radius,Area{
int radius;
public Circle(int radius){
this.radius = radius;
}
public int getLength(){
// Not applicable
return 0;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
return radius;
}
public double getArea(){
return 3.14* radius * radius;
}
}
public class InterfaceSeggration{
public static void main(String args[]){
Rectangle r = new Rectangle(10,20);
Square s = new Square(15);
Circle c = new Circle(2);
System.out.println("Rectangle area:"+r.getArea());
System.out.println("Square area:"+s.getArea());
System.out.println("Circle area:"+c.getArea());
}
}
주 : Rectangle
, Square
및 Circle
같은
이제 각각의 모양은 필요한 인터페이스를 구현하고 않은 사용 방법 제거되었다.
나는 이것에 -1 표를 던졌지 만 실제로 실수였다. 나는이 대답을 좋아한다 : D –
나는 의견이 적힌 투표에 대해 놀랐다. 시스템에서 허용하는 경우 수정할 수 있습니다. 그렇지 않으면 당신은 24 시간 후에 와야합니다 :) –
나는이 메시지를 가지고 있습니다 : ""당신은 마지막으로이 답변에 3 시간 전에 투표했습니다. 이 답변을 편집하지 않으면 투표가 잠겨 있습니다. ""따라서 메시지를 업데이트해야합니다.하지만 24 시간 내에 방문 할 수 있다면이 하향 투표를 삭제하겠습니다 : D –
IWorker 인터페이스 :
public interface IWorker {
public void work();
public void eat();
}
개발자 등급 :
public class Developer implements IWorker {
@Override
public void work() {
// TODO Auto-generated method stub
System.out.println("Developer working");
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("developer eating");
}
}
로봇 등급 :
public class Robot implements IWorker {
@Override
public void work() {
// TODO Auto-generated method stub
System.out.println("robot is working");
}
@Override
public void eat() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("cannot eat");
}
}
보다 완전한 예를 보려면 here으로 가십시오.
짧고 지점에 – Gordon
와우 .. 감사합니다! 캔트 다른 5 분 동의 : – hangar18
+1. 이 원리를 따르지 않는다는 것을 알려주는 고전적인 "냄새"는 클라이언트가 인터페이스의 메소드 중 일부만 호출하는 인터페이스를 사용하는 경우에 따라 달라집니다. – TrueWill