SOLID やその他の設計原則について読んでいました。ISPは「実装ではなく、インターフェースへのプログラム」と同じだと思いました。しかし、これらは異なる原則のように見えますか?
違いはありますか?
SOLID やその他の設計原則について読んでいました。ISPは「実装ではなく、インターフェースへのプログラム」と同じだと思いました。しかし、これらは異なる原則のように見えますか?
違いはありますか?
Robert Martin は、彼の著書「UML for Java Programmers」で、インターフェイス分離の原則 (ISP) について非常によく説明しています。それに基づいて、ISP は、論理的で首尾一貫した 1 つのグループに「焦点を合わせた」インターフェイスに関するものではないと思います。なぜなら、それは言うまでもありません。または、少なくとも言うまでもありません。各クラス、インターフェース、または抽象クラスは、そのように設計する必要があります。
それで、ISPとは何ですか?例を挙げて説明しましょう。クラス A と、クラス A のクライアントであるクラス B があるとします。クラス A に 10 個のメソッドがあり、そのうちの 2 つだけが B によって使用されているとします。B は、A の 10 個のメソッドすべてについて知る必要がありますか? ? おそらくそうではありません - 情報隠蔽の原則。公開すればするほど、カップリングのチャンスが生まれます。そのため、2 つのクラスの間にインターフェース (C と呼ぶ) を挿入することができます (分離)。そのインターフェイスは、B によって使用される 2 つのメソッドのみを宣言し、B は A に直接依存するのではなく、そのインターフェイスに依存します。
だから今、
class A {
method1()
method2()
// more methods
method10()
}
class B {
A a = new A()
}
となります
interface C {
method1()
method2()
}
class A implements C{
method1()
method2()
// more methods
method10()
}
class B {
C c = new A()
}
これにより、B が必要以上に知ることを防ぎます。
ISP は、個別のまとまりのある動作を表す各インターフェイスの概念に重点を置いています。
つまり、オブジェクトが行うべきことの各論理グループは、単一の特定のインターフェイスにマップされます。クラスはいくつかのことをしたいかもしれませんが、それぞれがその動作を表す特定のインターフェースにマップされます。アイデアは、各インターフェイスが非常に集中しているということです。
多くのメソッドを実装する 1 つのファット インターフェイスがあるとします。
そのファット インターフェイスを実装するすべてのクラスは、これらすべてのメソッドの実装を提供する必要があります。一部のメソッドは、その具象クラスに適用できない場合があります。しかし、インターフェイス分離の原則がない場合でも、実装を提供する必要があります。
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
、 、などのすべてのShape
実装に必要なメソッドを含む、汎用のファット インターフェイスです。ただし、それぞれの Shape チャイルドではいくつかのメソッドのみが必要ですRectangle
Circle
Square
Rectangle : getLength(), getWidth(), getArea()
Square : getLength() and getArea()
Circle : getRadius() and getArea()
分離がない場合、すべての Shape は Fat インターフェイス全体を実装しています: Shape.
次のようにコードを変更すると、インターフェース分離の原則で同じ出力を得ることができます。
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
実装し、未使用のメソッドを取り除きました。
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");
}
}
より完全な例については、こちらを参照してください。