このデモは「抽象化(アブストラクション)、継承(インヘリタンス)、多態性(ポリモーフィズム)、合成(コンポジション)」を具現化していますが、「抽象化(アブストラクション)、継承(インヘリタンス)、多態性(ポリモーフィズム)」の教材としては最適だと思われます。
オブジェクト指向プログラミングを もう少しガッツリやりたい場合は、下記で勉強してみると良いでしょう。
Javaデモ/CUI対戦デモ(10) オブジェクト指向プログラミング
http:../utf8/smt.cgi?r+sara/&bid+00000437&tsn+000004F7&bts+2021/02/08%2006%3A20%3A07&
集約とコンポジションの例えについて
https://qiita.com/gatapon/items/5e3292f897ab4f817001
>コンポジション
>保持されているものが保持しているものの一部である場合
>この書籍では「車とエンジン」で例えられています。
>集約
>独立して存在できる何かのコレクションがある場合
>こちらは空港と飛行機で例えられています。
その他の要件としては親オブジェクトが消滅する時に、確実に子オブジェクトも消滅するなら合成(コンポジション)と考えて良いです。
このデモはThreadやグラフィック表示のデモです、そして「抽象化(アブストラクション)、継承(インヘリタンス)、多態性(ポリモーフィズム)、合成(コンポジション」のデモでもあります。
あくまでもデモなので、手抜きをしています。
オブジェクト指向プログラミングの1番の肝は多態性(ポリモーフィズム)であり、その多態性(ポリモーフィズム)の肝は「共通の機能」(メソッド)を抽出することです(2番目の肝は「集約(アグリゲーション)、合成(コンポジション)」です)。
ちなみに肝となる「共通の機能」が複数 存在する場合もあります。
この場合は「Drawing()、DeltaMove()」が肝となる「共通の機能」となりますが、その肝となる「共通の機能」が抽出できるか どうかがオブジェクト指向プログラミングができるか どうかの基準になります。
肝となる「共通の機能」(メソッド)は、その機能ごとに完全にシグネチャが一致していなければなしません(コンストラクタや その他のメソッドは必ずしもシグネチャが一致しなくても良いです)。
「継承(インヘリタンス)」で対応できない場合に「集約(アグリゲーション)、合成(コンポジション)、委譲(デリゲーション)」などを使います、オブジェクト内に機能拡張用オブジェクトを作ることを「集約(アグリゲーション)、合成(コンポジション)」と言い、自オブジェクト・メソッド内で「集約(アグリゲーション)、合成(コンポジション)」オブジェクト・メソッドを呼び出している場合は委譲(デリゲーション)と言います。
この場合は「ArrayList<Figure> dalMember」は合成(コンポジション)、「Thread thread」も合成(コンポジション)になります。
このプログラムはスレッドを使っているので、排他制御(synchronized)も使っていますが、とりあえず排他制御(synchronized)はスルーしても良いです。
もし 排他制御(synchronized)を勉強したいなら、下記で勉強してみると良いでしょう。
Javaデモ/Swing「Sin グラフを横スクロールさせる」(007)
http:../utf8/smt.cgi?r+sara/&bid+00000632&tsn+00000632&bts+2022/04/30%2019%3A18%3A11&
(教材として参考にする場合は)とりあえず動きの部分は作らなくても良いので、図形の表示だけでも作ってみると良いでしょう。
動きの部分を作らなくても良いなら、「DeltaMove()」メソッドやスレッド関係は不要です。
このデモでは分かりやすさのために古いThreadを使っていますが、現在はThreadは実質的に非推奨になっています。
スレッドは「Concurrency Utilities」のスレッドが強く推奨されます。
(知らぬ間に)古いタイプのThreadが非推奨に?、(正式な非推奨では無いかもしれないが)そんなクズみたいなモノを何時までも使わないでくれよ、って話。
なお 新しいJavaでも古いタイプのThreadを使ってたら意味ないので注意して下さい。
下記 動画を参照して下さい、青色がCUPの未使用率、緑色がCUPの使用率だと思われます。
その動画のコンソール入力に注目すると、「ConcurrencyTest」を実行すると、CUPの使用率が ほぼ100%になり、圧倒的に効率が上がります(逆に言うと古いタイプのThreadが如何にクズかと言うことでも有りますが)。
Concurrency Utilities for EE 7
https://yoshio3.com/2013/05/15/concurrency-utilities-for-ee-7/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class J007 extends JFrame {
static String sAppTitle = "Java Application";
static J007 oAppFrame;
JPanel content;
// JPanel wpnlCanvas;
PnlCanvas wpnlCanvas;
ArrayList<Figure> dalCanvasMember = new ArrayList<Figure>();
/**
* Launch the application.
*/
public static void main(String[] args) {
// 以前はイベントもメイン・スレッドでしたが、
// イベントはイベント・ディスパッチ・スレッドに分離されたために、
// GUIコンポーネントの設定もイベント・ディスパッチ・スレッドで設定しなければならなくなったので、
// メイン・スレッドでのGUIコンポーネントの設定はNGになりました、
// 下記のように「EventQueue.invokeLater()」でイベント・ディスパッチ・スレッドに登録しなければなりません。
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
oAppFrame = new J007();
oAppFrame.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public J007() {
// 閉じるボタンをクリックされた場合の動作を設定
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(sAppTitle);
setLocation(50, 50);
int width = 500;
int height = 500;
// ContentPaneの実態はJFrameにビルトインされているデフォルト・パネル。
content = (JPanel) getContentPane();
content.setSize(width, height);
// 「JFrame#setSize(~)」でフレーム・サイズを設定すると、
// タイトルも含むウインドウ全体のサイズになります。
// つまり、ウインドウ内の表示領域の縦がタイトルのサイズ分 少なくなります。
// 「JFrame#getContentPane().setPreferredSize(~)」で設定し、
// 「pack()」すれば、ContentPaneで設定された全表示領域が表示されます。
content.setPreferredSize(content.getSize());
pack();
// content.setLayout(null);
content.setLayout(new BorderLayout());
dalCanvasMember.add(new Square(width / 2, 0, 0, 1, 100, Color.ORANGE));
dalCanvasMember.add(new Ball(width, height / 2, -1, 0, 50, Color.BLUE));
dalCanvasMember.add(new Ball(0, height / 2, 1, 1, 50, Color.GREEN));
dalCanvasMember.add(new Pentagram(width / 2, height, 1, -1, 50, Color.RED));
// wpnlCanvas001 = new JPanel();
wpnlCanvas = new PnlCanvas(dalCanvasMember);
getContentPane().add(wpnlCanvas, BorderLayout.CENTER);
wpnlCanvas.ThStart();
}
}
// Swing には JCanvas は存在しないので、
// グラフィックの描画には JPanel で代用する。
class PnlCanvas extends JPanel implements Runnable {
ArrayList<Figure> dalMember;
Thread thread;
int iSleep = 7; // ms
public PnlCanvas(ArrayList<Figure> cm) {
dalMember = cm;
thread = new Thread(this);
}
public void ThStart() {
thread.start();
}
@Override
public synchronized void paint(Graphics g) {
int width, height;
width = getSize().width;
height = getSize().height;
g.clearRect(0, 0, width, height);
for (int i = 0; i < dalMember.size(); i++) {
dalMember.get(i).Drawing((Graphics2D) g);
}
}
@Override
public void run() {
int width, height;
loop: while (true) {
repaint();
try {
Thread.sleep(iSleep);
} catch (InterruptedException ex) {
break loop;
// ex.printStackTrace();
}
width = getSize().width;
height = getSize().height;
synchronized (this) {
for (Figure o : dalMember) {
o.DeltaMove(width, height);
}
}
}
thread = null;
// スレッドの終了時には、必ずスレッド変数にnullを代入する。
}
}
abstract class Figure {
double fX, fY;
double dX, dY;
Color oBackColor = null;
public Figure(double x, double y, double dx, double dy, Color bc) {
setPosition(x, y);
setDelta(dx, dy);
setBackColor(bc);
}
public void setBackColor(Color bc) {
oBackColor = bc;
}
public void setDelta(double x, double y) {
dX = x;
dY = y;
}
public void setPosition(double x, double y) {
fX = x;
fY = y;
}
public void DeltaMove(double w, double h) {
double x, y;
x = fX + dX;
y = fY + dY;
if (x < 0 | w < x) {
dX = -dX;
}
if (y < 0 | h < y) {
dY = -dY;
}
x = fX + dX;
y = fY + dY;
setPosition(x, y);
}
abstract public void Drawing(Graphics2D g2);
};
class Square extends Figure {
double fEdge = 0;
public Square(int x, int y, double dx, double dy, int eg, Color bc) {
super(x, y, dx, dy, bc);
fEdge = eg;
}
@Override
public void Drawing(Graphics2D g2) {
double half = fEdge / 2;
g2.setColor(oBackColor);
double x, y, w, h;
x = fX - half;
y = fY - half;
Rectangle2D rectangle = new Rectangle2D.Double(x, y, fEdge, fEdge);
g2.fill(rectangle);
}
};
class Ball extends Figure {
double fRadius = 0;
public Ball(double x, double y, double dx, double dy, double r, Color bc) {
super(x, y, dx, dy, bc);
fRadius = r;
}
@Override
public void Drawing(Graphics2D g2) {
g2.setColor(oBackColor);
double x, y, w, h;
x = fX - fRadius;
y = fY - fRadius;
w = fRadius * 2;
h = fRadius * 2;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
g2.fill(ellipse);
}
};
class Pentagram extends Ball {
public Pentagram(double x, double y, double dx, double dy, double r, Color bc) {
super(x, y, dx, dy, r, bc);
}
@Override
public void Drawing(Graphics2D g2) {
// Coordinate
int[] a1iCoordX, a1iCoordY;
a1iCoordX = new int[5];
a1iCoordY = new int[5];
// 「Canvasで五芒星を書く」より。
// https://qiita.com/nasum/items/a59f2ee4df4fd2f24227
g2.setColor(oBackColor);
double[] degree = { -90, -234, -18, -162, -306 };
for (int i = 0; i < degree.length; i++) {
a1iCoordX[i] = (int) (fX + fRadius * Math.cos(degree[i] / 180 * Math.PI));
a1iCoordY[i] = (int) (fY + fRadius * Math.sin(degree[i] / 180 * Math.PI));
}
Polygon polygon = new Polygon(a1iCoordX, a1iCoordY, a1iCoordX.length);
g2.fill(polygon);
}
}
|
|