UML クラス図は構造図であり、システムの静的構造を記述するためによく使用されます。通常、UML クラス図には、クラスの UML 図、インターフェイスの UML 図、汎化関係の UML 図、関連関係の UML 図、依存関係の UML 図、およびインターフェイスの UML 図が含まれます。実現関係。
クラス UML ダイアグラム
クラスのUML図では、クラスの主な構成を四角形で記述し、その四角形を縦に3層に分けます。
最初のレイヤーはレイヤーという名前で、クラス名が通常フォントの場合はそのクラスが具象クラスであることを示し、クラス名が斜体フォントの場合はそのクラスが抽象クラスであることを示します。
2 番目の層は変数層であり、属性層とも呼ばれ、クラスのメンバ変数と型を一覧表示します。形式は「変数名:型」です。UML でクラスを表現する場合、最も重要なメンバ変数のみを使用できます。デザインの必要に応じてリストされます。
変数のアクセス許可が public の場合は、変数名の前に「+」記号を付けて変更する必要があります。
変数のアクセス許可が保護されている場合は、変数名の前に「#」記号を使用する必要があります。
変数のアクセス許可が非公開の場合は、変数名の前に「-」記号を付けて変更する必要があります。
変数のアクセス権が Friendlyの場合、変数名の前に記号は使用されません。
3 番目のレイヤーはメソッド レイヤー (操作レイヤーとも呼ばれます) で、クラスのメソッドと戻り値の型が一覧表示されます。形式は「メソッド名 (パラメーター リスト): 型」です。
UML クラスを使用する場合、設計の必要性に応じて、最も重要なメソッドのみをリストできます。
メソッドのアクセス権が public の場合、メソッド名の前に「+」記号を付けて変更する必要があります。
メソッドのアクセス許可は protected で 、「#」記号で装飾されています。
メソッドのアクセス権は非公開で、「-」記号で装飾されています。
メソッドのアクセス権が Friendly の場合、メソッド名の前に記号は使用されません。
メソッドが静的メソッドの場合は、メソッド名に下線を引きます。
インターフェイスを表す UML ダイアグラム
長方形を使用して、3 つのレイヤーに分割されたインターフェイスの主な構成を説明します。
最初のレイヤーは名前レイヤーです.インターフェイスの名前はイタリック体である必要があり,名前は <<interface>> で変更する必要があります.
2 番目のレイヤーは定数レイヤーで、インターフェイス内の定数と型がリストされ、形式は "定数名: 型" です。
インターフェイス内の定数のアクセス権は公開されており、定数名は「+」記号で装飾されています。
3 番目のレイヤーはメソッド レイヤー (操作レイヤーとも呼ばれます) で、インターフェイスにメソッドと戻り値の型が一覧表示され、形式は "メソッド名 (パラメーター リスト): 型" です。インターフェイス内のメソッドのアクセス権はパブリックであり、「+」記号はメソッド名を変更するために使用されます。
汎化関係
一般化とは、クラスの継承関係を指します。クラスが別のクラスのサブクラスである場合、UML は、 2 つのクラスの UML 図を、サブクラスの UML 図から始まり、サブクラスの UML 図で終わる実線で結ぶことによって、2 つのクラス間の継承関係を表します。親クラスの UML ダイアグラムですが、端点に中空の三角形があり、実線の終わりを示しています。
例: Animal クラスとその 2 つのサブクラス Dog と Cat の UML ダイアグラム
接続関係
クラス A のメンバー変数がクラス B (インターフェイス) によって宣言された変数である場合、A と B の間の関係は関連付けであり、A が B に関連付けられていることを意味します。A が B に関連している場合、UML は、A の UML ダイアグラムから始まり、B の UML ダイアグラムで終わる実線を使用して、A と B の UML ダイアグラムを接続しますが、A の最後で B を指す UML ダイアグラムを使用します。方向矢印は実線の終点を示します。
例: Light クラスに関連付けられた ClassRoom クラスの UML ダイアグラム。
依存関係
クラス A のメソッドのパラメーターがクラス B (インターフェイス) で宣言された変数であるか、メソッドによって返されるデータ型が型 B である場合、A と B の関係は依存関係であり、A は B に依存します。A が B に依存している場合、UML は A と B の UML 図を点線で結びます. 点線の始端が A の UML 図であり、点線の終点が B の UML 図です.ただし、終点は B の UML ダイアグラムを指す方向矢印を使用します。破線の終点を示します。
ClassRoom は Student インターフェイスの UML ダイアグラムに依存します
A が B にメソッド パラメータを介して依存していることを強調する必要がある場合は、UML 図で破線を使用して、UML 図で A と B を接続します。
関係を築く
クラスがインターフェースを実装する場合、クラスとインターフェースの間の関係は実現であり、これはクラスがインターフェースを実装すると呼ばれます。UMLはクラスとそれが実装するインターフェースを点線で結びます. 点線の始端はクラスであり, 点線の終端は実装するインターフェースですが, 端は白抜きの三角形で表します.点線の終わり。
Create インターフェースを実装する ClassOne および ClassTwo クラスの UML ダイアグラム
ノート:
UML は注釈 (Annotation) を使用して、クラス図に追加の指示を提供します。UML は、与えられた注釈を丸められた長方形で表示し、破線を使用して丸められた長方形を注釈を付けるエンティティに接続します。
例: Computer クラスの add() メソッドのアノテーションを使用する Computer クラスの UML ダイアグラム
オブジェクト指向の原則
抽象クラスとインターフェース
抽象 (抽象) クラスには、次の特徴があります。
(1)抽象クラスは、抽象メソッドまたは非抽象メソッドを持つことができます。
(2)抽象クラスは new 演算子を使用してオブジェクトを作成できません。
(3) 非抽象クラスが抽象クラスのサブクラスである場合、親クラスの抽象メソッドをオーバーライドする必要があります
(4)遷移オブジェクトの構成: 抽象クラスは new 演算子を使用してオブジェクトを作成することはできませんが、その非抽象サブクラスはその抽象メソッドをすべて書き直して、抽象クラスによって宣言されたオブジェクトが上遷移オブジェクトになることを許可する必要があります。そのサブクラス オブジェクトを呼び出し、クラスによってオーバーライドされたメソッドを呼び出します。
例: 抽象クラス A に抽象メソッド add(int x, int y) があります。
A.java
public abstract class A {
public abstract int add(int x,int y);
}
B.java
public class B extends A{
public int add(int x,int y) {
return x+y;
}
}
アプリケーション.java
public class Application {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a;
a = new B(); //a是B类对象的上转型对象
int m = a.add(3, 2);//a调用子类B重写的add()方法
System.out.println(m);
}
}
インターフェース
インターフェイスには次の特徴があります。
(1) インターフェースの public パーミッションを持つ抽象メソッド、デフォルト メソッド、および静的メソッド
(2) インターフェースがクラスによって実装され、クラスがインターフェースを実装する場合、インターフェース内の抽象メソッドを書き換える必要があります。
(3) インターフェースコールバック: インターフェースコールバックとは、インターフェースを実装するクラスのオブジェクトの参照を、インターフェースによって宣言されたインターフェース変数に割り当てることを指し、インターフェース変数は、クラスによって書き換えられたインターフェースメソッドを呼び出すことができます。
次のインターフェイス Com には、抽象メソッド sub(int x, int y) があります。
Com.java
public interface Com {
public abstract int sub(int x,int y);
}
ComImp.java
class ComImp implements Com {
public int sub(int x,int y) {
return x-y;
}
}
アプリケーション.java
public class Application {
public static void main(String args[]) {
Com com;
com = new ComImp();//com变量存放ComImp类的对象的引用
int m = com.sub(8,2); //com回调ComImp类实现的接口方法
System.out.println(m); //输出结果为6
}
}
出力結果: 6
抽象指向プログラミング
クラスを設計するときは、このクラスを抽象クラスまたはインターフェース クラスに直面させます。つまり、クラス内の重要なデータは、抽象クラスまたはインターフェース クラスによって宣言された変数です。
例: 既に Circle クラスがあり、このクラスによって作成されたオブジェクト circle は getArea() メソッドを呼び出して、円の面積を計算します。
public class Circle {
double r;
Circle(double r){
this.r = r;
}
public double getArea() {
return(3.14*r*r);
}
}
public class Pillar {
double height;
Circle bottom; //将Circle对象作为成员,bottom是用具体类Circle声明的变量
Pillar(Circle bottom,double height){
this.bottom = bottom;
this.height = height;
}
public double getVolume() {
return bottom.getArea()*height;
}
}
上記の Pillar クラスでは、bottom は具体的なクラス Circle で宣言された変数です. ユーザー要件の変更を伴わない場合、上記の Pillar クラスの設計に問題はありませんが、ユーザーは Pillar クラスが作成できることを望んでいます.底が三角形の円筒。上記の Pillar クラスは、そのような列を作成できません。つまり、上記の設計された Pillar クラスは、ユーザーのニーズを満たすことができません。
Pillar クラスを再設計します。まず第一に, 円柱の体積を計算するための鍵は底の面積を計算することであることに注意してください. 円柱の底の面積を計算するとき, 人はその底の特定の形状を気にするべきではありません. 、ただし、図に面積を計算する方法があるかどうかのみ。したがって、Pillar クラスを設計するときは、特定のクラスで宣言された変数をその下に置かないでください。
次に、抽象化のために Pillar クラスを再設計します。最初に、抽象 getArea() メソッドを定義する抽象クラス Geometry (またはインターフェース) を記述します。
public abstract class Geometry { //如果使用接口,需用interface来定义Geometry
public abstract double getArea();
}
これで、Pillar クラスは Geometry クラスのコードを記述できるようになりました。つまり、Pillar クラスは Geometry オブジェクトを独自のメンバーとして使用する必要があり、このメンバーは Geometry サブクラスによって書き換えられた getArea() メソッドを呼び出すことができます。
Pillar クラスの設計は具象クラスに依存しなくなり、Geometry クラスに向けられています。つまり、Pillar クラスの下部は、具象クラスによって宣言された変数ではなく、抽象クラス Geometry で宣言された変数です。
public class Pillar {
double height;
Geometry bottom; //将Circle对象作为成员,bottom是用具体类Circle声明的变量
Pillar(Geometry bottom,double height){
this.bottom = bottom;
this.height = height;
}
public double getVolume() {
return bottom.getArea()*height; //bottom可以调用子类重写的getArea方法
}
}
public class Retangle extends Geometry{
double a,b;
Retangle(double a,double b){
this.a = a;
this.b = b;
}
public double getArea() {
return a*b;
}
}
public class Circle extends Geometry {
double r;
Circle(double r){
this.r = r;
}
public double getArea() {
return(3.14*r*r);
}
}
public class Application {
public static void main(String[] args) {
// TODO Auto-generated method stub
Pillar pillar;
Geometry bottom;
bottom = new Retangle(22,100);
pillar = new Pillar(bottom,58);
System.out.println("矩形底体积:"+pillar.getVolume());
bottom = new Circle(10);
pillar = new Pillar(bottom,60); //pillar是具有圆形底的柱体
System.out.println("圆形底的体积:"+pillar.getVolume());
}
}
操作結果:
長方形ベースの体積: 127600.0
円形ベースの体積: 18840.0
抽象化のために Pillar クラスを設計することにより、Pillar クラスは具象クラスに依存しなくなります。、Triangle サブクラスの追加など、システムが新しい Geometry サブクラスを追加するときはいつでも、Pillar クラスのコードを変更することなく、Pillar を使用して三角形の底面を持つ円柱を作成できます。
「開閉」の原則
いわゆる「Open-Closed Principle」(Open-Closed Principle)とは、ユーザーのデザインを「拡張に対してオープンで、変更に対してクローズド」にすることです。
本質とは、新しいモジュールを設計に追加するときに、既存のモジュールを変更する必要がないことを意味します。デザインをするときは、ユーザーニーズの変化を第一に考え、ユーザーの変化に対応する部分は自由に展開できるように設計し、デザインの核となる部分は熟慮の上で決定された基本構造であり、部品は変更できないようにクローズする必要があります はい、つまり、ユーザーのニーズの変化により変更することはできません。
たとえば、図に示すように、4 つのクラス UML クラス図があります。
この設計の Geometry クラスと Pillar クラスは、変更のためのシステムの閉じた部分ですが、Geometry のサブクラスは拡張のための開いた部分です。Geometry サブクラスをシステムに追加する場合 (拡張可能)、Pillar を使用して、Pillar クラスを変更せずに、新しい Geometry サブクラスの指定されたベースを持つ列を作成できます。
メソッドを再利用するための 2 つの手法: クラスの継承とオブジェクトの合成
サブクラスは、親クラスのメソッドを独自のメソッドの 1 つとして継承します。このメソッドは、サブクラスで宣言された任意のインスタンス メソッドから呼び出すことができます。
親クラスのメソッドは、継承の方法でサブクラスで再利用できます。
継承によって親クラスのメソッドを再利用する利点は、サブクラスが親クラスのメソッドをオーバーライドできることです。つまり、再利用されたメソッドを簡単に変更または拡張できます
。
継承によるメソッドの再利用のデメリットは次のとおりです。
(1) 親クラスからサブクラスに継承されるメソッドはコンパイル時に決定されるため、親クラスから継承されたメソッドの動作は実行時に変更できません。
(2)サブクラスと親クラスの関係は強い結合関係
. 親クラスのメソッドの振る舞いが変わると、必然的にサブクラスの変化につながる.
(3)継承による再利用は「ホワイトボックス」再利用とも呼ばれます. 欠点は、親クラスの内部の詳細がサブクラスに見えることです.
複合多重化
クラスは、オブジェクトを独自のメンバー変数として使用できます.そのようなクラスを使用してオブジェクトを作成すると、オブジェクト内に他のオブジェクトが存在し、オブジェクトは他のオブジェクトを独自のコンポーネントとして使用します (これはよく言われることです) Has-A) 、またはオブジェクトが複数のオブジェクトで構成されています。
オブジェクト a がオブジェクト b を結合する場合、オブジェクト a はオブジェクト b にそのメソッドを呼び出すよう委任できます。つまり、オブジェクト a は結合された方法でオブジェクト b のメソッドを再利用します。
オブジェクトを組み合わせてメソッドを再利用する利点は
次のとおりです。 (1) オブジェクトを組み合わせてメソッドを再利用することは、「ブラック ボックス」の再利用とも呼ばれます。これは、現在のオブジェクトは、含まれているオブジェクトにのみそのメソッドの呼び出しを委ねることができ、現在のオブジェクトに含まれているオブジェクトのみを委託できるためです。メソッドの詳細は、現在のオブジェクトには表示されません。
(2)現在のオブジェクトに含まれるオブジェクトのクラスのコードを変更すると、現在のオブジェクトのクラスのコードを変更する必要がないため、オブジェクトと含まれるオブジェクトは弱い結合関係に属します。
(3) 現在のオブジェクトは、ピラーの組み合わせの下部オブジェクトなど、実行時に含まれるオブジェクトを動的に指定でき、下部は実行時に Circle オブジェクトまたは Rectangle オブジェクトとして指定できます。
以下は、車のドライバーの動的交換をシミュレートします
person.java
public abstract class Person {
public abstract String getMess();
}
車.java
public class Car {
Person person; //组合驾驶员
public void setPerson(Person p) {
person = p;
}
public void show() {
if(person == null) {
System.out.println("没人驾驶");
}
else {
System.out.println("驾驶人是:");
System.out.println(person.getMess());
}
}
}
MainClass.java
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car car = new Car();
int i=1;
while(true) {
try {
car.show();
Thread.sleep(2000); //每个2000毫秒更换驾驶员
Class<?>cs = Class.forName("Driver"+i);
Person p = (Person)cs.getDeclaredConstructor().newInstance(); //无人驾驶或当期驾驶员继续驾驶
car.setPerson(p); //更换驾驶员
i++;
}catch(Exception exp) {
i++;
}
if(i>10) i=1;
}
}
}
Person クラス サブクラス プログラムの編集を続けます。サブクラス名は Drive1、Drive2 にする必要があります。. . .
public class Driver1 extends Person{
public String getMess() {
return "我是美国驾驶员";
}
}
public class Driver5 extends Person {
public String getMess() {
return "我是女驾驶员";
}
}
操作結果:
誰も運転していません
運転手は:
私は米国の運転手です
運転手は:
私は米国の運転手です
運転手は:
. . . .