20210606のJavaに関する記事は7件です。

新入社員研修用にWebアプリを作ろうとしているお話【TDDでじゃんけん実装】

目的 久々に本社に戻ったら新入社員がいて、一応研修という名目で勉強していたが、 教える側も学ぶ側もどうすればよいのかわかっていなかったように見えた。 そのため、新人教育と自分の勉強も兼ねて、Spring FrameworkでじゃんけんができるWebアプリを実装してみる。 単に自分の興味を引くテーマだったっていうのと個人で勝手にやっているということから、 業務外のプロジェクトなのでかなりの低速進行になりそう。 あと、本人のJavaは7年前に行ったAndroid開発で止まっているので、 今のJavaの書き方と比較しておかしいところがあれば教えていただけると助かります。 特にパッケージの切り方とか。 仕様考察 とりあえず、話を聞いていたらJava+Spring Frameworkは確定で、できればSQLも使いたいアプリを作ろうとしているとのことだった。 それを踏まえたら下記のような仕様のアプリを作れば良さそうだ。 Webでじゃんけんができるようにする 使用環境はJava + Spring Framework(多分Spring Boots) 対戦相手はCPUで、CPUはランダムな手を出す ローカルマシンでじゃんけんできれば良い(ユーザとか、セッションとか考える必要はないとする) 過去の成績を表示できるようにする(SQLで) 全期間の通算成績を表示できるようにする 過去N戦(とりあえずN=10)の戦績も表示できるようにする TDDでじゃんけんを実装する せっかくだし、TDD(テスト駆動開発)でじゃんけんのロジックを実装する。 参考にしたのは下記書籍。 じゃんけんのToDoりすと 今回、下記のToDoリストでスタートした。 じゃんけんのToDoリスト じゃんけんを行う CPUの手をセットする 数字を指定すれば対応する手になる 数字を指定しなければランダムに出す プレイヤーの手をセットする じゃんけんの3すくみを行う あいこを実装する ヘルプを表示する 3つの手があることをわかるようにする 過去の勝率を表示する 通算成績を表示する 最近10戦を表示する WebGUIのToDoリスト じゃんけんを行う画面の実装 じゃんけん前の画面の実装 勝敗を表示する画面の実装 過去の勝率を表示する画面の実装 じゃんけんの手 テスト まずは下記の2つのテストを作成しよう。 CPUの手をセットする 3つの手があることをわかるようにする じゃんけんの手はグー、チョキ、パーの3つであり、それ以外は含まれないから、その2点をテストに落とし込む。 また、じゃんけんの勝敗などの管理はJankenModelクラスを作成し、そこに実装することにした。 アノテーションについては下記の記事がわかりやすい、かもしれない。 package personal.mickie.janken.Model; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Arrays; public class JankenModelTest { private JankenModel model; private final String ROCK = "グー"; private final String SCISSORS = "チョキ"; private final String PAPER = "パー"; @BeforeEach void SetUp() { model = new JankenModel(); } @Test void testHandList() { // じゃんけんの手は3つ assertEquals(model.getHands().length, 3); // グー、チョキ、パーが含まれる assertTrue(Arrays.asList(model.getHands()).contains(ROCK)); assertTrue(Arrays.asList(model.getHands()).contains(PAPER)); assertTrue(Arrays.asList(model.getHands()).contains(SCISSORS)); } @Test void testSetHand(){ // グー:1、チョキ:2、パー:3として実装する model.setCpuHand(1); assertEquals(model.getCpuHandName(), ROCK); model.setCpuHand(2); assertEquals(model.getCpuHandName(), SCISSORS); model.setCpuHand(3); assertEquals(model.getCpuHandName(), PAPER); } } 実装 じゃんけんの手を示すためのクラスとCPUの手を示すためのクラスと2つが必要そうなので、テストを満たすように実装を行う。 じゃんけんの手は下記の通り、列挙型を作っておいた。 JankenHands.java package personal.mickie.janken.Model; import java.util.ArrayList; import java.util.List; public enum JankenHands { ROCK("グー", 1), SCISSORS("チョキ",2), PAPER("パー",3); private String handName; private int handId; private JankenHands(String handName, int handId) { this.handName = handName; this.handId = handId; } public String getHandName() { return this.handName; } public int getHandId() { return this.handId; } public static final String[] getHandsName() { List<String> result = new ArrayList<String>(); for (JankenHands hand : JankenHands.values()) { result.add(hand.getHandName()); } return result.toArray(new String[result.size()]); } public static final JankenHands GetHandFromCode(int code) { for (JankenHands hand : JankenHands.values()) { if (hand.handId == code) { return hand; } } throw new IllegalArgumentException("じゃんけんの手は1~3までの数でお願いします。"); } } CPUの手はモデルに持たせることにする。この実装は下記の通り。 JankenModel.java package personal.mickie.janken.Model; public class JankenModel { public String[] getHands() { String[] result = JankenHands.getHandsName(); return result; } private JankenHands cpuHand; public void setCpuHand(int handCode) { setCpuHand(JankenHands.GetHandFromCode(handCode)); } public void setCpuHand(JankenHands hand) { cpuHand = hand; } public String getCpuHandName() { return cpuHand.getHandName(); } public JankenModel() { cpuHand = null; } } じゃんけんの勝敗 テスト じゃんけんの勝ち負けの実装は注意しなければ勝ち負け逆になりそうだ。 最低限の全組み合わせを出すなら次のとおりだろうか。 CheckHandは、プレイヤー目線でCPUの手と勝負した結果とした。 @Test void testHandStrength() { // CPUがグーを出している状態で、 model.setCpuHand(JankenHands.ROCK); // プレイヤーがパーを出していれば勝ち JankenHands playerHand = JankenHands.PAPER; assertEquals(model.CheckResult(playerHand), JankenResult.Win); // プレイヤーもグーなら引き分け playerHand = JankenHands.ROCK; assertEquals(model.CheckResult(playerHand), JankenResult.Draw); // プレイヤーがチョキなら負け playerHand = JankenHands.SCISSORS; assertEquals(model.CheckResult(playerHand), JankenResult.Lose); // 上記組み合わせで足りていない手の組み合わせを実装 model.setCpuHand(JankenHands.PAPER); assertEquals(model.CheckResult(playerHand), JankenResult.Win); // CPUとプレイヤーで逆の手を出したら勝ち負けも逆になる。(ただし引き分け以外) playerHand = JankenHands.ROCK; assertEquals(model.CheckResult(playerHand), JankenResult.Lose); } 実装 テストではJankenModelの結果を確認しているが、じゃんけんの手の強弱なのだから、 強弱の実装はJankenHandsにもたせてJankenModelは利用するだけにする。 そうなってくると、JankenHands.javaにこのような実装を追加し、 public JankenResult getResult(JankenHands oppornentHand) { if (this.getHandId() == oppornentHand.getHandId()) { return JankenResult.Draw; }else if (this.getHandId() % 3 == (oppornentHand.getHandId() - 1) % 3) { return JankenResult.Win; }else { return JankenResult.Lose; } } JankenModel.javaにはこのメソッドを呼び出すための実装をもたせる。 public JankenResult CheckResult(JankenHands playerHand) { return playerHand.getResult(cpuHand); } 現時点での実装状況 じゃんけんのToDoリストは下記の通り。 じゃんけんを行う CPUの手をセットする 数字を指定すれば対応する手になる 数字を指定しなければランダムに出す プレイヤーの手をセットする じゃんけんの3すくみを行う あいこを実装する ヘルプを表示する 3つの手があることをわかるようにする 過去の勝率を表示する 通算成績を表示する 最近10戦を表示する この記事の時点での実装状況は下記においておいた。 ※この時点ではまだWebアプリとしては動かないはず。 次回はWebアプリ側の実装に手を出す予定。(ランダムのテストってどうやったものかな…)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TemplateMethodパターン ~同じ手順のひな型を使う~

TemplateMethodパターンとは GoFの23個のデザインパターンのうちの1つである。 (GoF、デザインパターンとは何ぞやという人はこちらを参照。) スーパークラスに処理の流れを定義し、具体的な処理の内容をサブクラスで実装する。それによって手順に変更があった場合に、修正範囲をスーパークラスだけに局所化できるというメリットがある。 アンチパターン(悪い例) TemplateMethodパターンを使うと何が嬉しいのかという点について、まずアンチパターンを考えてみる。処理の共通部分の多いHoge/Fooクラスがありメソッドfunc1とfunc2を順に呼び出す。もし処理の順序を逆にするような仕様変更が入った場合、Hoge/Fooクラスの両方に対して修正とテストが必要になってしまう。 Hoge.java package TemplateMethod; public class Hoge { public void func1(){ System.out.println("Hoge func1");} public void func2(){ System.out.println("Hoge func2");} public void execute() { func1(); func2(); } } Foo.java package TemplateMethod; public class Foo { public void func1(){ System.out.println("Foo func1");} public void func2(){ System.out.println("Foo func2");} public void execute() { func1(); func2(); } } TemplateMethodパターンの仕組み TemplateMethodパターンのクラス図を記載する。 スーパークラスとしてFugaを定義し、execute()メソッドの中であらかじめfunc1()/func2()の実行手順を定めておく。Hoge/Fooクラスではそれぞれfunc1()/func2()をオーバーライドして実装する。これによってもしfunc1()/func2()の実行順や実行回数に仕様変更があった場合もスーパークラスであるFugaクラスのexecute()メソッドだけを修正すればよい。例が簡易すぎてメリットが実感しずらいかもしれないが、前処理、メイン処理、後処理のように複数のクラスの処理の流れが似ている場合にこのパターンが有効である。 TemplateMethodパターンをインスタンス生成に応用したのがFactoryMethodパターンである。TemplateMathodパターンでは「継承」を利用してプログラムの動作を変更した。これに対してStrategyパターンでは「委譲」を利用してプログラムの動作を変更することができる。 ソースコード SuperFuga.java package TemplateMethod; public abstract class SuperFuga { public abstract void func1(); public abstract void func2(); // スーパークラスで処理の流れをあらかじめ決めておく。 // サブクラスの処理の流れを変更したい場合はここだけ変更すればOK public final void execute() { this.func1(); this.func2(); } } Hoge.Java package TemplateMethod; public class Hoge extends SuperFuga { @Override public void func1(){ System.out.println("Hoge func1");} @Override public void func2(){ System.out.println("Hoge func2");} } Foo.Java package TemplateMethod; public class Foo extends SuperFuga { @Override public void func1(){ System.out.println("Foo func1");} @Override public void func2(){ System.out.println("Foo func2");} } Main.Java package TemplateMethod; public class Main { public static void main(String args[]) { // ここでHoge/Fooクラスのインスタンスは必ずスーパークラスの型に代入する // オブジェクト指向の3大要素の1つであるポリモーフィズム(多態性)を活用している。 SuperFuga f = new Hoge(); SuperFuga f2 = new Foo(); f.execute(); f2.execute(); } } 実行結果. Hoge func1 Hoge func2 Foo func1 Foo func2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PLATEAUのCityGMLからMVTを作成する作業の記録

1.概要 インディゴ株式会社さんの下記のエントリを参考に、PLATEAUのCityGMLから建物のMapbox Vector Tile(MVT)を作ってみました。 その作業記録です。 2.CityGMLからGeojsonを生成 PlateauのCityGMLを読み込み、Geojsonを生成するユーティリティを作成しました。 CityGMLの読み込みはcitygml4j、geojson生成はgsonを使用しています。 geojsonは、建物のLOD0FootPrintからgeometryを作成し、GenericAttributeからpropertiesを作成しています。 CiryGMLのフォルダを指定してCityGMLUtilを実行すると、同じフォルダにgeojsonファイルが生成されます。 CityGMLUtil.java import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.citygml4j.CityGMLContext; import org.citygml4j.builder.jaxb.CityGMLBuilder; import org.citygml4j.builder.jaxb.CityGMLBuilderException; import org.citygml4j.model.citygml.CityGML; import org.citygml4j.model.citygml.CityGMLClass; import org.citygml4j.model.citygml.building.Building; import org.citygml4j.model.citygml.core.AbstractCityObject; import org.citygml4j.model.citygml.core.CityModel; import org.citygml4j.model.citygml.core.CityObjectMember; import org.citygml4j.model.citygml.generics.AbstractGenericAttribute; import org.citygml4j.model.citygml.generics.IntAttribute; import org.citygml4j.model.citygml.generics.MeasureAttribute; import org.citygml4j.model.citygml.generics.StringAttribute; import org.citygml4j.model.gml.geometry.aggregates.MultiSurface; import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty; import org.citygml4j.model.gml.geometry.primitives.DirectPositionList; import org.citygml4j.model.gml.geometry.primitives.Exterior; import org.citygml4j.model.gml.geometry.primitives.LinearRing; import org.citygml4j.model.gml.geometry.primitives.Polygon; import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty; import org.citygml4j.xml.io.CityGMLInputFactory; import org.citygml4j.xml.io.reader.CityGMLReadException; import org.citygml4j.xml.io.reader.CityGMLReader; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class CityGMLUtil { public static void readCityGML(File f,List<Map<String,Object>> list) throws CityGMLBuilderException, CityGMLReadException{ CityGMLContext ctx = CityGMLContext.getInstance(); CityGMLBuilder builder = ctx.createCityGMLBuilder(); CityGMLInputFactory in = builder.createCityGMLInputFactory(); CityGMLReader reader = in.createCityGMLReader(f); while (reader.hasNext()) { CityGML citygml = reader.nextFeature(); if (citygml.getCityGMLClass() == CityGMLClass.CITY_MODEL) { CityModel cityModel = (CityModel)citygml; for (CityObjectMember cityObjectMember : cityModel.getCityObjectMember()) { AbstractCityObject cityObject = cityObjectMember.getCityObject(); if (cityObject.getCityGMLClass() == CityGMLClass.BUILDING){ Building b=(Building)cityObject; if(b.getMeasuredHeight()!=null){ list.add(createFeature(b)); } } } } } reader.close(); } private static Map<String,Object> createFeature(Building b){ Map<String,Object> ret=new HashMap<>(); ret.put("type","Feature"); Map<String,Object> geom=new HashMap<>(); Map<String,Object> prop=new HashMap<>(); ret.put("geometry",geom); ret.put("properties",prop); geom.put("type","Polygon"); MultiSurfaceProperty msp=b.getLod0FootPrint(); MultiSurface ms=msp.getMultiSurface(); List<SurfaceProperty> spl=ms.getSurfaceMember(); Polygon pp=(Polygon)spl.get(0).getGeometry(); Exterior ex=(Exterior)pp.getExterior(); LinearRing lr=(LinearRing)ex.getRing(); DirectPositionList dpl=(DirectPositionList)lr.getPosList(); List<Double> dl=dpl.toList3d(); List<double[]> tmp=new ArrayList<>(); double dem=0.0; for(int i=0;i<dl.size();i=i+3){ Double d01=dl.get(i); Double d02=dl.get(i+1); Double d03=dl.get(i+2); tmp.add(new double[]{d02,d01}); dem=d03; } List<List<double[]>> c=new ArrayList<>(); c.add(tmp); geom.put("coordinates",c); prop.put("measuredHeight",b.getMeasuredHeight().getValue()); List<AbstractGenericAttribute> ll=b.getGenericAttribute(); for(AbstractGenericAttribute at : ll){ if(at instanceof StringAttribute){ StringAttribute st=(StringAttribute)at; prop.put(st.getName(), st.getValue()); }else if(at instanceof MeasureAttribute){ MeasureAttribute st=(MeasureAttribute)at; prop.put(st.getName(), st.getValue().getValue()); }else if(at instanceof IntAttribute){ IntAttribute st=(IntAttribute)at; prop.put(st.getName(), st.getValue()); } } prop.put("dem", dem); return ret; } public static void main(String[] args){ File in=new File(args[0]); //CityGMLのディレクトリ try { Gson gson=new GsonBuilder().setPrettyPrinting().create(); for(File f : in.listFiles()){ if(f.isDirectory())continue; if(f.getName().toLowerCase().endsWith(".gml")){ System.out.println(f.getName()); Map<String,Object> root=new HashMap<>(); root.put("type", "FeatureCollection"); List<Map<String,Object>> list=new ArrayList<>(); root.put("features", list); readCityGML(f,list); try { File out=new File(f.getAbsolutePath().replace(".gml", ".geojson")); BufferedWriter bw=new BufferedWriter(new FileWriter(out)); bw.write(gson.toJson(root)); bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } catch (CityGMLBuilderException e) { e.printStackTrace(); } catch (CityGMLReadException e) { e.printStackTrace(); } } } 3.Mapbox Vector Tile生成 生成したgeojsonから、tippecanoeを使用してMVTを生成します。 tippecanoeについては、インディゴ株式会社さんの先のエントリの他、@frogcatさんの下記エントリを参考にしました。 geojsonのディレクトリで下記のコマンドを実行すると、指定したフォルダ(下記ではpbf)にMVTデータ(レイヤー名はbldg)が出力されます。 tippecanoe --no-tile-compression -ad -an -Z12 -z16 -e ../pbf -l bldg -ai *.geojson 4.成果物 Plateauの『3D都市モデル(Project PLATEAU)大阪市(2020年度)』をMVTに変換した結果です。 建物外郭線(LOD0)を建物高さで立ち上げたLOD1相当のデータですが、3Dtilesに比べて軽く動作する感じです。 なお、大阪市のMVTタイルの容量は、ズームレベル12~16で、120MBでした。 5.最後に PLATEAUはとても興味深いのですが、3DTilesはジオイドの関係でdeck.gl、maplibre、mapboxでは使いづらかったので、何かうまい方法はないかなと考えていたところでした。 Twitterでインディゴ株式会社さんのGithubを知り、「こんな事ができるんだ」と目からうろこでした。素晴らしい情報をありがとうございます! 試しに大阪市データからMVTを作ってみると、非常に簡単に作れたので、ちょっと色々と試してみたくなりました。 また、国土基盤情報の建物外郭線と兵庫県全域数値地形図のようなDSM・DEMがあれば、同じようなLOD1相当の建物データが作れそうに感じました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

web技術に入門してみた。

備忘録的な意味合いの強い web技術の基礎をまとめておくことにした。 そもそもwwwは 欧州原子核研究機構CERN が、研究成果をメールに頼らず、 いつでも誰でもアクセスできるようにするために発明されたものである。 当時は簡単なHTML文章をただ返す、根本的な機能しか持っておらず、 そこで新たな問題が発生した。 せっかくHTMLを公開しても、 閲覧者が飽きてしまい、アクセスが減るという問題である。 また、コンテンツの更新に莫大な手間がかかり、キリが無いという問題も付随して発生した。 そこで開発されたのがCGIという技術で、 動的コンテンツをweb上で閲覧できるシステムだ。 現在のwebアプリケーションの土台になっている。 最初はC言語やPerlが用いられていたが、やがてそれらを踏襲してJavaが発明され、受け入れられるようになっていく。 ここで新たな問題が発生する。 webアプリケーションの大規模化、複雑化である。 Amazon.comを想像すると分かりやすいが、 従来のアプリケーションとは比較にならないほど複雑で、 かつ規模が大きく、便利なものを、従来のシステムで管理できないことだ。 我々初学者が勉強に一番の時間を割く、 webフレームワークの登場へと、話は展開される。 webフレームワーク登場初期、 一番の問題はログイン状態をいかに保持しておくか、 というものだった。 普段から何気なく使っている。 Cookieの誕生である。 webサーバからwebブラウザへHTTPレスポンスを利用して小さな情報を送る。 名前と値の組み合わせ、これがcookieである。 一方cookieを受け取ったものと異なるサーバーからは、 アクセスを拒否する。 これを利用してログイン状態が管理されている。 しかしセキュリティ上の問題を払拭することができなかった。 簡単な仕組みであるが故に、 第三者からユーザー名、パスワードを知られてしまうと、本人になりすまして買い物したり、 銀行口座をのぞかれてしまう。 これらを解決するために生み出されたのがsession である。 銀行の窓口を想像すると分かりやすいが、 例えAさんが新規に口座を開設するとして、 その旨を担当員に伝えると、整理券番号Aでお待ち下さいと言われる。 その間にBさんの要件を受け付け、処理をすることができる。 そうこうしている内に新規口座の開設手続きは終わり、 Aさんはスムーズに通帳を受け取ることができる。 ログイン→処理→内容確認→ログアウト この一連の流れをsession、ここで言う受け付け番号をsessionIDと呼ぶ。 受け付け番号で管理する点、cookieよりもセキュアであると言えるし、 cookieが持つやりとりの機能を再利用することができる。 例えばwordで何か文章を作成するケースを考える。 この場合PCが一台あれば完結するが、 webアプリケーションの場合同様にはいかない。 webサーバーとwebクライアント、少なくとも2台のコンピュータが必要である。 システムも以前より大規模化を迫られる。 大量のデータを保持するにあたって発明されたのが、 おなじみDatabaseである。 初学者にも有名な機能がCRUDである。 create,read,update,deleteを指す言葉であるが、 データベースサーバーを経由することで、 データを抽出しやすくなる。 ここからはアプリケーションサーバーの登場から、 アプリケーションを安全に運用するための仕組みである、 SSHの誕生へと、発展していく。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bridgeパターン ~機能の拡張から実装への橋渡し~

Bridgeパターンとは GoFの23個のデザインパターンのうちの1つである。 (GoF、デザインパターンとは何ぞやという人はこちらを参照。) Bridgeパターンでは継承を「機能のクラス階層」と「実装のクラス階層」の2つに分けて考え、それらを独立して管理することで機能の拡張を容易にするプログラム設計の考え方の一つである。 通常継承の目的は以下のいずれかもしくは両方である。 1. スーパークラスの抽象メソッドをサブクラスで実装すること。(機能の実装) 2. スーパークラスの機能をサブクラスで拡張すること。(機能の拡張) Bridgeパターンでは機能拡張と実装を分離し、それらを独立して管理するため、「機能のクラス階層」と「実装のクラス階層」に分けて考える。 アンチパターン(悪いやり方) Bridgeパターンを使うと何が嬉しいのかという点について、まずアンチパターンを考えてみる。 Animalクラスというスーパークラスがあり、それを継承するDogクラスとCatクラスが存在する。 Animalクラスにペットとして価格を表示する機能(dispPrice())を追加する場合、Animalクラスを継承するPetクラスを作ることをまず考える。 この場合、PetクラスからはDog/Catクラスの実装をそのまま使用することはできない。(Animalを継承しているので、抽象メソッドは存在するが、Dog/Catクラスの実装がない。) したがって、PetクラスにdispPrice()を追加すると、Petクラスを継承するDog'クラスとCat'クラスを作らなくてはならなくなる。Petクラスに機能(fuga())を追加したHogeクラスを作ると、さらにDog''/Cat''クラスを作らなくてはならなくなり、クラス数が積算的に増加していってしまう。結果、拡張性の低いクラス群ができてしまう。このような問題を解決するのがBridgeパターンである。 Bridgeパターンの仕組み 以下にクラス図を記載する。Bridgeパターンのポイントは以下の通り。 ・BridgeパターンではOOP(オブジェクト指向プログラム)の「継承」「集約」「インターフェイス」の概念を活用している。 ・ポイントはSpeakAbleインターフェイスを追加し、それを実装するDog/Catクラスを定義すること。 ・AnimalクラスはSpeakAbleインターフェイスを実装したオブジェクトをフィールドとして持ち(集約)し、そのオブジェクトを通じてDog/Catクラスのspeak()を呼ぶ。 ・Animalクラスは抽象メソッドを持たないため、Animalクラスを継承したPetクラスはspeak()を実装する必要がない。 ・Dog/Catクラスの動物の種類に依存している鳴き声の部分を、「実装のクラス階層」で表現することで、「機能のクラス階層」側でいくら機能を追加してもDog/Catクラスに同時に対応したことになる。 ソースコード Animal.Java package DsignPattern; public class Animal { // SpeakAbleインターフェイスをフィールドとして持つ private SpeakAble impl; public Animal(SpeakAble impl){ this.impl = impl; } // フィールドのApeakAbleインターフェイスを実装したオブジェクトのspeak()を呼ぶ public void speak() { this.impl.speak(); } } Pet.Java package DsignPattern; public class Pet extends Animal { private int price; public Pet(SpeakAble impl, int price) { super(impl); this.price = price; } // 価格を表示する機能を追加 public void dispPrice() { System.out.println("Price:" + price); } } SpeakAble.Java package DsignPattern; interface SpeakAble { public abstract void speak(); } Dog.Java package DsignPattern; public class Dog implements SpeakAble { @Override public void speak(){ System.out.println("わんわん"); } } Cat.Java package DsignPattern; public class Cat implements SpeakAble { @Override public void speak(){ System.out.println("にゃーにゃー"); } } Main.Java package DsignPattern; public class Main { public static void main(String args[]) { Animal a1 = new Animal(new Dog()); Animal a2 = new Pet(new Dog(), 50_000); Pet a3 = new Pet(new Dog(), 50_000); Pet a4 = new Pet(new Cat(), 100_000); a1.speak(); a2.speak(); a3.speak(); // 追加した機能が「すべての実装」で利用できる! a3.dispPrice(); a4.speak(); // 追加した機能が「すべての実装」で利用できる! a4.dispPrice(); } } わんわん わんわん わんわん Price:50000 にゃーにゃー Price:100000
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】関数型インターフェース(Function)の使い方

Functionインターフェースとは? Functionは1つの引数(Type T)を受けて、1つのオブジェクト(Type R)を返す関数型インターフェースです。 public interface Function<T, R> { R apply(T t); } 使い方 以下の例では、func1のapply()メソッドにHelloを引数として渡すことで、Hello World!が返されます。 import java.util.function.Function; public class FunctionExample1 { public static void main(String[] args) { Function<String, String> func1 = x -> x + " World!"; String result = func1.apply("Hello"); System.out.println(result); // Hello World! } } 以下は、匿名クラスでFunctionインターフェースを使用する例です。 import java.util.function.Function; public class FunctionExample2 { //不規則なリストを作成 List<Integer> randomNumbers = new ArrayList<>(Arrays.asList(378,121,190)); //リストをソートするメソッドを定義 List<Integer> sortedList = new Function<List<Integer>,List<Integer>>() { @Override public List<Integer> apply(List<Integer> randomNumbers ) { Collections.sort(randomNumbers); return randomNumbers; } //不規則なリストを引数として渡す }.apply(randomNumbers); //ソート済のリストを出力 for (Integer sortedNum:sortedList) { System.out.println(sortedNum); //121 190 378 } } 参照 Java Platform SE8 #Function
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

主要RDB の JDBCドライバは Maven Repository からダウンロード可能

Java, JDBC, Maven 関連記事です。 ちょっとした小ネタです。 主要RDB の JDBCドライバの多くは Maven Repository からダウンロードすることができるようになっています。 つまり JDBC ドライバは pom.xml などにおける依存関係の指定によって自動ダウンロードすることが可能なのです。 Java 経験の長い人ほど、あるいはオンプレの仕事がメインの方にとっては、この状況が意外かも知れません。私自身、プロプライエタリ系のJDBCドライバが Central から入手可能になったのには驚きました。(昔は状況がまるで違っていた) このような傾向は、クラウド前提など時代の要請から実現されているのかもしれません。これは、クラウド上でのビルドの際に、Maven Repository Central に依存および解決できることが望まれるためかも知れませんね。 理由や経緯はともかく、JDBC ドライバを Maven Repository からダウンロードできるのは利便性良くとても快適です。 主要なRDBのJDBCドライバ 主要な RDB の JDBC ドライバの Maven Repository ランディングページを以下に示します。 (*) 他にも主要RDBはいろいろありますが、記述はここまでで割愛します。 RDB JDBC  License PostgreSQL https://mvnrepository.com/artifact/org.postgresql/postgresql BSD 2-clause MySQL https://mvnrepository.com/artifact/mysql/mysql-connector-java GPL 2.0 Microsoft SQL Server https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc MIT Oracle https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 Oracle Free Use Terms and Conditions (FUTC) IBM DB2 https://mvnrepository.com/artifact/com.ibm.db2/jcc International Program License Agreement (IPLA) pom.xml 記述組み込み例 Maven Repository 上の JDBC ドライバを 実際の Maven pom.xml に記述する例は、たとえば以下のような記述になります。 JDBC ドライバを pom.xml に記述する例 初出: 2021-06-06
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む