今からはじめるプログラミング40

連載?の最後です。

 

口を追加してみると(みなくても)、
サブクラスで実装したメソッドの中も同じような記述が出てくる。
例えば、ファイルの読み込みと出力は違うのはファイル名だけ?が違っている。とか。
なので、抽象かクラスの中身(粒度の大きい部分)も変更する。
ファイル名を取得するメソッド(からで実装)をつくり、読み込みと書き出しは抽象化クラスで描いてしまう。
するとサブクラス側で読み書きは実装の必要がなくなるので、ファイル名を設定するメソッドを埋める。
そんな感じで、スーパーとサブをいったりきたりしながら、システムを構成するクラスを完成させていく。

できあがったものは、
abstractクラス(ModImage)
--------------------------------
package sample21;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public abstract class  ModImage {
    
    protected abstract boolean modImage() ;

    protected abstract String outFileName();

    protected abstract String inFileName();
    
    protected  boolean outImage() {
        System.out.println("outImage()を実行");
        // 出力
        try {
            ImageIO.write(this.img, "png", new File(outFileName()));
        } catch (IOException e) {
            System.out.println("画像を出力できませんでした。");
            return false;
        }
        return true;
    }
    
    protected boolean loadImage() {
        //画像を読み込む。
        try {
            this.img = ImageIO.read(new File(inFileName()));
        } catch (IOException e) {
            System.out.println("画像を読み込めませんでした。");
            return false;
        }
    
        return true;
    }
    
    
    protected BufferedImage img = null;
    
    
    public boolean execute() {
        if(this.loadImage()) {
            if(this.modImage()) {
                if(this.outImage()) {
                    return true;
                }else {
                    return false;
                }
            }else {
                return false;
            }
        }else {
            return false;
        }
    }

}
------------------------------------
そして、サブクラス(めとはなとくち)


------------------------------------
package sample21;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;

public class AddEye extends ModImage  {

    protected boolean modImage() {
        System.out.println("modImage()を実行");
        //目をつければキャラクターっぽくなる?
        Graphics2D g = this.img.createGraphics();
        g.setColor(Color.WHITE);
        g.setFont(new Font("Verdana", Font.BOLD, 25));
        g.drawString("●", 150, 400);
        g.drawString("●", 250, 400);
        return true;
    }
    @Override
    protected String outFileName() {
        
        return "./out.png";
    }

    @Override
    protected String inFileName() {
        
        return "./img.png";
    }
}
-----------------------------------

はな
-----------------------------------
package sample21;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;

public class AddNouse extends ModImage {

    @Override
    protected boolean modImage() {
        System.out.println("modImage()を実行");
        //目をつければキャラクターっぽくなる?
        Graphics2D g = this.img.createGraphics();
        g.setColor(Color.WHITE);
        g.setFont(new Font("Verdana", Font.BOLD, 25));
        g.drawString("花", 200, 450);
        return true;
    }

    @Override
    protected String outFileName() {
        return "./add_nouse.png";
    }
    
    @Override
    protected String inFileName() {
        
        return "./out.png";
    }
    
}

-----------------------------------

くち
-----------------------------------
package sample21;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;

public class AddMouse extends ModImage {

    @Override
    protected boolean modImage() {
        System.out.println("modImage()を実行");
        //口の書き出し
        Graphics2D g = this.img.createGraphics();
        g.setColor(Color.WHITE);
        g.setFont(new Font("Verdana", Font.BOLD, 25));
        g.drawString("○", 200, 500);
        return true;
    }

    @Override
    protected String outFileName() {
        return "./add_mouse.png";
    }
    
    @Override
    protected String inFileName() {
        
        return "./add_nouse.png";
    }
    
}

-----------------------------------

で、この段階でmainメソッドを外に切り出しました。
------------------------------------
package sample21;

public class MainClass {

    public static void main(String arguments[]) {
        System.out.println("目の追加の実行");
        ModImage modI = new AddEye();
        if (modI.execute()) {
            System.out.println("目の追加正常に実行できた");
        } else {
            System.out.println("目の追加しっぱいした");
        }
        System.out.println("花の追加の実行");
        ModImage modN = new AddNouse();
        if (modN.execute()) {
            System.out.println("花の追加正常に実行できた");
        } else {
            System.out.println("花の追加しっぱいした");
        }
        ModImage modM = new AddMouse();
        if (modM.execute()) {
            System.out.println("口の追加正常に実行できた");
        } else {
            System.out.println("口の追加しっぱいした");
        }
    }
}

------------------------------------

最後にわかりずらくぶっ飛んでいた位置を修正して、実行した結果です。

f:id:yo2an:20211001010644p:plain

目鼻口が追加されました。

 

どうだろうか。。。

狭い視点では、スーパーとサブを行ったり来たり。

大きな視点では、設計(クラスの関係)をちょこちょこ変更しながら。

実際は、設計の方は、頭の中でやるイメージでしょうかね。

最初からこんな感じで抽象クラスをイメージできると、

サブクラスの実装が楽ですね。

というかこの形は、デザインパターンでテンプレートメソッドというものになっていて、Javaビジネスロジックの実装でよく使われる?ものみたいです。

実際の開発では画面もロジックも数十は作ると思いますが、

フロント(UI)側とロジック側で作る人を分担して、

フロントのUI/UX開発とロジックはDBがわかっている人、得意な人が開発するということもありありです。

業務アプリケーションの開発は範囲がひろくて、全部できる人をフルスタックエンジニアとかいったりしますが、そんなスーパーな人が必ずいるわけでもないし、僕みたいにほぼ新人でいきなり難しい画面作らされたりもしますので、システムの構成要素ごとの作業分担は、どこでもやっています。

メンテナンス性の高いアプリケーションということでも、役割がきちんと明確になっていると、いざ障害が発生したという場合にも修正箇所の特定もやりやすいでしょう。

そんな感じでアプリケーションを開発しやすいようにしたものにフレームワークというものがありますが、これも業務アプリケーションの構成をきれいに整理して、エンジニアはアプリケーションの目的に沿った部分を作り込んでいくだけでアプリが作れる、ということを追求したものといえます。DIコンテナとか。

話がだいぶ大きくなりましたが、いちおう業務アプリケーション開発に参入される方に参考になればと思いました。