- JAVA
- 技術 💻
デザインパターンの使いどころ|GoF23の一覧と実務でよく使う8つ
デザインパターンとは、設計でくり返し現れる問題と、その解決の形に名前を付けて整理したものです。代表的なのが、1994年に4人の著者(Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides。通称GoF=Gang of Four)がまとめた23のパターンです。
デザインパターンは23個すべてを同じ重さで覚える必要はなく、実務で出番が多いのは一部です。また、Javaのラムダ式やDIコンテナ(Springなど)の普及で、「クラスを自作しなくても、言語やフレームワークがすでに実現している」パターンも増えました。この記事では、23パターンの一覧で全体像をつかんだうえで、実務でよく使う8つについて、使いどころ・使わない場面・Java標準ライブラリやSpringでの実例を、Java 21で動かした実行結果つきで解説します。
デザインパターンの使いどころ早見表
| 困っていること | 使うパターン | Java・Springでの身近な例 |
|---|---|---|
| アルゴリズムや方針を、状況に応じて差し替えたい | Strategy | Comparator、Spring Securityの PasswordEncoder |
| 処理の流れは同じで、一部の手順だけ違う | Template Method | java.util.AbstractList、java.io.InputStream |
| 引数が多いオブジェクトを、読みやすく安全に作りたい | Builder | HttpRequest.newBuilder()、RestClient.builder() |
| 作るクラスの決定を、子クラスや設定に任せたい | Factory Method | Collection.iterator() |
| 既存の部品のインターフェースが、こちらの期待と合わない | Adapter | Arrays.asList()、InputStreamReader |
| 元のクラスを変えずに、機能を重ねて足したい | Decorator | BufferedInputStream、GZIPInputStream |
| ある出来事を、複数の処理に知らせたい | Observer | Springの @EventListener |
| インスタンスを1つだけにしたい | Singleton(注意して使う) | Runtime.getRuntime()、Springのシングルトンスコープ |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「デザインパターンの使いどころ|GoF23の一覧と実務でよく使う8つ」
GoF 23パターンの一覧
GoFのパターンは、目的によって生成・構造・振る舞いの3つに分類されます。「実務での出番」は、現在のJava・Spring中心の開発で、自分で設計・実装する機会の多さの目安です。
生成に関するパターン(5つ):オブジェクトの作り方
| パターン | ひとことで | 実務での出番 |
|---|---|---|
| Abstract Factory | 関連する部品の「セット」をまとめて作る | △ |
| Builder | 複雑なオブジェクトを段階的に組み立てる | ◎ |
| Factory Method | 何を作るかを子クラスに決めさせる | ○ |
| Prototype | 既存のオブジェクトをコピーして作る | △ |
| Singleton | インスタンスを1つだけに限定する | ○(多くはDIコンテナに任せる) |
構造に関するパターン(7つ):クラスやオブジェクトの組み合わせ方
| パターン | ひとことで | 実務での出番 |
|---|---|---|
| Adapter | 合わないインターフェースを変換してつなぐ | ◎ |
| Bridge | 「機能の階層」と「実装の階層」を分けて、別々に増やせるようにする | △ |
| Composite | 部分と全体(木構造)を同じように扱う | ○ |
| Decorator | 包むことで機能を重ねて追加する | ◎ |
| Facade | 複雑な仕組みに、簡単な入口を1つ用意する | ○ |
| Flyweight | 同じ内容のオブジェクトを共有してメモリを節約する | △(Integer のキャッシュなど標準で実現) |
| Proxy | 代理のオブジェクトを通してアクセスを制御する | ○(Springが自動で作る) |
振る舞いに関するパターン(11個):処理の分担と流れ
| パターン | ひとことで | 実務での出番 |
|---|---|---|
| Chain of Responsibility | 処理できる担当者まで、要求を順に回す | ○(サーブレットのフィルターなど) |
| Command | 命令をオブジェクトにして、保存・実行・取り消しできるようにする | ○(Runnable など) |
| Interpreter | 簡単な言語の文法をクラスで表し、解釈する | △ |
| Iterator | 中身の構造を見せずに、順に取り出す | ◎(拡張for文で日常的に使う) |
| Mediator | 多数のオブジェクトのやり取りを、仲介役に集める | △ |
| Memento | 状態を保存し、あとで元に戻せるようにする | △(取り消し機能など) |
| Observer | 状態の変化を、登録された相手に通知する | ◎ |
| State | 状態ごとの振る舞いを、状態クラスに分ける | ○ |
| Strategy | アルゴリズムを差し替え可能にする | ◎ |
| Template Method | 処理の骨組みを親で決め、一部を子で実装する | ○ |
| Visitor | データ構造を変えずに、新しい処理を追加する | △(Java 21ではsealed+switchで代替しやすい) |
全体の骨格は「生成=作り方」「構造=組み合わせ方」「振る舞い=処理の分担」と覚えると、一覧が整理しやすくなります。
実務でよく使うパターン
Strategy:方針を差し替える
Strategyは、「何をするか(アルゴリズム)」をオブジェクトとして外から渡せるようにするパターンです。Javaで最も身近な例は Comparator です。List.sort() は並べ替えの仕組みだけを持ち、「何の順に並べるか」は Comparator(戦略)として渡します。
record Item(String name, int price, int stock) {}
List<Item> items = new ArrayList<>(List.of(
new Item("ノート", 300, 50), new Item("ペン", 120, 200), new Item("ファイル", 300, 10)));
// 並べ替えの「戦略」だけを差し替える(Comparator が Strategy)
Comparator<Item> byPrice = Comparator.comparingInt(Item::price);
Comparator<Item> byPriceThenStock = byPrice.thenComparingInt(Item::stock);
items.sort(byPrice);
System.out.println("価格順: " + items.stream().map(Item::name).toList());
items.sort(byPriceThenStock);
System.out.println("価格→在庫少ない順: " + items.stream().map(Item::name).toList());
価格順: [ペン, ノート, ファイル]
価格→在庫少ない順: [ペン, ファイル, ノート]
| 使いどころ | 使わない場面 |
|---|---|
| 計算方法・並べ替え・検証ルールなどが複数あり、実行時や設定で切り替える | 分岐が2つで、今後も増える予定がない(if文のほうが読みやすい) |
同じ if/switch の分岐が複数の場所にある |
戦略ごとの処理が1行で、ラムダ式で十分なとき(クラスを作らなくてよい) |
Springでは、同じインターフェースの実装を複数Beanとして登録し、設定や条件で選ぶ形でよく使います。Spring Securityの PasswordEncoder(BCryptPasswordEncoder などを差し替える)もStrategyです。
Java 8以降は、ラムダ式がそのまま戦略になるため、インターフェースと実装クラスを毎回作る必要はありません。
Factory Method:作るものを子クラスに決めさせる
Factory Methodは、「処理の手順は親クラスが決め、その中で使うオブジェクトの生成だけを子クラスに任せる」パターンです。
// 手順(export)は親が決め、「何を作るか」(createJoiner)は子クラスが決める
abstract class Exporter {
final String export(List<String> rows) {
StringJoiner j = createJoiner(); // ← Factory Method
rows.forEach(j::add);
return j.toString();
}
protected abstract StringJoiner createJoiner();
}
class CsvExporter extends Exporter {
protected StringJoiner createJoiner() { return new StringJoiner(","); }
}
class JsonExporter extends Exporter {
protected StringJoiner createJoiner() { return new StringJoiner("\",\"", "[\"", "\"]"); }
}
for (Exporter e : List.of(new CsvExporter(), new JsonExporter())) {
System.out.println(e.export(List.of("a", "b")));
}
a,b
["a","b"]
Java標準では、Collection.iterator() が代表例です。ArrayList と HashSet はそれぞれ自分に合ったIteratorを作り、使う側は具体的なクラスを知りません。
混同しやすい点として、List.of() や Integer.valueOf() のような「staticファクトリメソッド」は、GoFのFactory Methodとは別物です。staticファクトリメソッドは「コンストラクターの代わりに、名前の付いたstaticメソッドで生成する」という書き方(書籍『Effective Java』で推奨)で、子クラスに生成を任せる仕組みではありません。
| 使いどころ | 使わない場面 |
|---|---|
| フレームワークやライブラリを作り、生成するものを利用者に拡張させたい | 生成するクラスが1つだけ(new で十分) |
| 手順は共通で、使う部品だけが種類ごとに違う | DIコンテナで実装を差し替えられる場合(Springでは設定で選ぶほうが簡単) |
Builder:引数の多いオブジェクトを安全に組み立てる
Builderは、オブジェクトの組み立てを段階的に行い、最後に build() で完成させるパターンです。引数が多いコンストラクター(new Report("月次", 30, true, false, null, …))は、どの値が何の意味かを読み取れず、順番の間違いにも気づきにくいという問題があります。
// 自作の Builder:必須項目と任意項目を分け、build() でまとめてチェック
record Report(String title, int pageSize, boolean landscape) {
static class Builder {
private final String title;
private int pageSize = 50;
private boolean landscape = false;
Builder(String title) { this.title = title; }
Builder pageSize(int v) { this.pageSize = v; return this; }
Builder landscape(boolean v) { this.landscape = v; return this; }
Report build() {
if (title.isBlank()) throw new IllegalStateException("title は必須です");
return new Report(title, pageSize, landscape);
}
}
}
Report r = new Report.Builder("月次レポート").pageSize(30).landscape(true).build();
System.out.println(r);
try {
new Report.Builder("").build();
} catch (IllegalStateException e) {
System.out.println("エラー: " + e.getMessage());
}
Report[title=月次レポート, pageSize=30, landscape=true]
エラー: title は必須です
必須項目はBuilderのコンストラクターで受け取り、任意項目はメソッドで設定し、build() で整合性をまとめてチェックするのが基本の形です。完成したオブジェクトは変更できない(イミュータブル)ようにします。
| 使いどころ | 使わない場面 |
|---|---|
| 任意の項目が多い(目安として4〜5個以上) | 項目が2〜3個なら、recordのコンストラクターで十分 |
| 組み立ての途中は不完全でよく、完成時にまとめて検証したい | すべての項目が必須で、順番の取り違えが起きにくい |
Java標準では HttpRequest.newBuilder(uri).timeout(...).header(...).POST(...).build()、Springでは RestClient.builder() や WebClient.builder() など、設定項目の多いクラスの多くがBuilderを提供しています。
Adapter:合わない形を変換してつなぐ
Adapterは、既存の部品のインターフェースを、こちらが期待する形に変換する「変換プラグ」のようなパターンです。変更できない既存コードや外部ライブラリを、自分のシステムに組み込むときに使います。
interface Temperature { double celsius(); } // こちらのシステムが期待する形
class LegacySensor { // 変更できない既存の部品(華氏を返す)
double readFahrenheit() { return 77.0; }
}
class FahrenheitAdapter implements Temperature { // 形を合わせる変換役
private final LegacySensor sensor;
FahrenheitAdapter(LegacySensor sensor) { this.sensor = sensor; }
public double celsius() { return (sensor.readFahrenheit() - 32) * 5 / 9; }
}
// Java標準:配列を List として扱う Adapter(元の配列と連動する)
String[] arr = {"a", "b", "c"};
List<String> view = Arrays.asList(arr);
view.set(0, "z");
System.out.println("配列も変わる: " + Arrays.toString(arr));
try { view.add("d"); } catch (UnsupportedOperationException e) { System.out.println("add は不可: " + e); }
現在の気温: 25.0℃
配列も変わる: [z, b, c]
add は不可: java.lang.UnsupportedOperationException
Arrays.asList() は配列をListの形で見せる変換役なので、set は元の配列に反映され、要素数を変える add はできません。Adapterは「形を変えるだけで、中身は元のまま」という性質がよくわかる例です。バイト列を文字として読む InputStreamReader もAdapterです。
| 使いどころ | 使わない場面 |
|---|---|
| 外部ライブラリや既存システムの形を、自分のコードに持ち込まないようにしたい | 自分で変更できるコード同士(インターフェース自体を直すほうが簡単) |
| ライブラリを将来差し替える可能性がある | 変換が1か所だけで、今後も増えない |
Spring MVCの内部では、HandlerAdapter が、形の違うさまざまなハンドラー(コントローラー)を共通の方法で呼び出すために使われています。
Decorator:包んで機能を重ねる
Decoratorは、同じインターフェースを持つオブジェクトで「包む」ことで、元のクラスを変えずに機能を追加するパターンです。Java標準の入出力(java.io)が代表例で、new BufferedReader(new InputStreamReader(new GZIPInputStream(in), UTF_8)) のように、「展開する」「文字に変換する」「行単位で読む」機能を包んで重ねていきます。
// 自作:同じインターフェースを持つ部品で包み、処理を足す
interface Notifier { void send(String msg); }
class Chat implements Notifier {
public void send(String msg) { System.out.println(" [チャット] " + msg); }
}
class Logging implements Notifier {
private final Notifier inner;
Logging(Notifier inner) { this.inner = inner; }
public void send(String msg) { System.out.println(" log: 送信開始"); inner.send(msg); System.out.println(" log: 送信終了"); }
}
Notifier n = new Retry(new Logging(new Chat()), 2); // Retry(失敗時に再送)も同じ形の Decorator。定義は省略
n.send("デプロイ完了");
log: 送信開始
[チャット] デプロイ完了
log: 送信終了
ログ、リトライ、キャッシュ、計測のような「本来の処理の前後に足したいもの」を、組み合わせ自由な部品にできるのが強みです。継承で LoggingRetryChat のようなクラスを組み合わせの数だけ作る必要がなくなります。
| 使いどころ | 使わない場面 |
|---|---|
| 追加したい機能が複数あり、組み合わせを自由に変えたい | 追加する機能が1つだけで固定 |
| 元のクラスを変更できない、または変更したくない | 包む層が深くなりすぎて、処理の流れを追えなくなる |
Springでは、トランザクションやキャッシュのような「前後に足す処理」は、Decoratorを自作するより、AOP(@Transactional、@Cacheable)に任せるのが一般的です。これはSpringが自動で作るProxyの仕組みです(後述)。
Observer:出来事を複数の相手に知らせる
Observerは、ある出来事(イベント)が起きたとき、登録されている相手(リスナー)にまとめて通知するパターンです。通知する側は、誰が聞いているかを知らなくてよいのがポイントです。
class OrderEvents {
private final List<Consumer<String>> listeners = new ArrayList<>();
void subscribe(Consumer<String> l) { listeners.add(l); }
void placed(String orderId) { listeners.forEach(l -> l.accept(orderId)); }
}
var order = new OrderEvents();
order.subscribe(id -> System.out.println("在庫: 注文 " + id + " の在庫を引き当て"));
order.subscribe(id -> System.out.println("メール: 注文 " + id + " の確認メールを送信"));
order.subscribe(id -> System.out.println("ポイント: 注文 " + id + " にポイント付与"));
order.placed("A-001"); // 注文側は、誰が聞いているかを知らない
在庫: 注文 A-001 の在庫を引き当て
メール: 注文 A-001 の確認メールを送信
ポイント: 注文 A-001 にポイント付与
「注文後にポイントも付けたい」という変更は、リスナーを1つ追加するだけで済み、注文の処理は変わりません。
Java標準の java.util.Observable と Observer は、Java 9で非推奨(deprecated)になっています。実際にコンパイルすると、次の警告が出ます。
ObservableDemo.java:3: warning: [deprecation] Observable in java.util has been deprecated
現在は、自分でリスナーのリストを持つ(上の例)、Springの ApplicationEventPublisher と @EventListener、非同期のデータの流れなら java.util.concurrent.Flow などを使います。
| 使いどころ | 使わない場面 |
|---|---|
| 1つの出来事に、独立した後続処理が複数ある | 処理の順番や、すべて成功したかどうかが重要(明示的に順に呼ぶほうが安全) |
| 後続処理が今後も増えそう | 通知先が1つだけ |
通知の流れはコードから追いにくくなるため、「どのイベントを、誰が受け取っているか」を一覧で把握できるようにしておくと、保守しやすくなります。
Template Method:処理の骨組みを固定する
Template Methodは、処理の流れ(骨組み)を親クラスで決め、一部の手順だけを子クラスで実装するパターンです。
abstract class ImportJob {
// 処理の流れ(テンプレート)は親が固定する。final で上書きを防ぐ
final void run(List<String> lines) {
int ok = 0;
for (String line : skipHeader(lines)) {
if (!valid(line)) { System.out.println("スキップ: '" + line + "'"); continue; }
save(parse(line)); ok++;
}
System.out.println("取り込み件数: " + ok);
}
protected List<String> skipHeader(List<String> lines) { return lines.subList(1, lines.size()); } // 既定の動き(フック)
protected boolean valid(String line) { return !line.isBlank(); }
protected abstract String[] parse(String line); // 子クラスが決める部分
protected abstract void save(String[] cols);
}
class CsvImport extends ImportJob {
protected String[] parse(String line) { return line.split(","); }
protected void save(String[] c) { System.out.println("保存: id=" + c[0] + " name=" + c[1]); }
}
new CsvImport().run(List.of("id,name", "1,ノート", "", "2,ペン"));
保存: id=1 name=ノート
スキップ: ''
保存: id=2 name=ペン
取り込み件数: 2
Java標準では、AbstractList(get と size だけ実装すれば、残りのメソッドが使える)や、InputStream(1バイト読む read() を実装すれば、配列に読む read(byte[]) が使える)がこの形です。
Springの JdbcTemplate は名前に「Template」とありますが、継承ではなく、処理の一部(RowMapper など)をコールバックとして渡す形です。同じ「骨組みは固定、一部だけ差し替え」を、継承の代わりにStrategy(渡す)で実現しています。現在は、継承より、このコールバック方式のほうが柔軟で、よく選ばれます。
| 使いどころ | 使わない場面 |
|---|---|
| 手順の順番を必ず守らせたい(前処理→本処理→後処理) | 子クラスごとの違いが大きく、骨組みを共有できない |
| 種類ごとの違いが、一部の手順に限られる | 継承の階層が深くなる(コールバックで渡す形を検討) |
Singleton:使う前に注意したいパターン
Singletonは、あるクラスのインスタンスが1つだけであることを保証するパターンです。Java標準では Runtime.getRuntime() が代表例です。Javaで自作する場合は、enum で書くのが最も安全(シリアライズやリフレクションでも2つ目が作られない)とされています。
一方で、状態を持つSingletonは、プログラム全体から触れる「グローバル変数」と同じ性質を持ちます。テストが互いに影響し合う例を見てみます。
enum Counter { // enum で書くのが最も安全な Singleton
INSTANCE;
private int count;
void increment() { count++; }
int value() { return count; }
}
System.out.println("Runtime は同じ? " + (Runtime.getRuntime() == Runtime.getRuntime()));
Counter.INSTANCE.increment(); // テストA
System.out.println("テストAの後: " + Counter.INSTANCE.value());
Counter.INSTANCE.increment(); // テストB(1 を期待しているが…)
System.out.println("テストBの後: " + Counter.INSTANCE.value() + "(テストBは 1 を期待)");
Runtime は同じ? true
テストAの後: 1
テストBの後: 2(テストBは 1 を期待)
テストの実行順によって結果が変わり、テスト用の偽物にも差し替えられません。
Spring Bootでは、Beanは標準で「シングルトンスコープ」(1つのコンテナにつき1つ)です。ただしこれはGoFのSingletonとは違い、クラス自身は普通のクラスのままで、コンテナが1つだけ作って配ってくれます。テストでは別のインスタンスや偽物を渡せるため、「1つだけにしたい」ならDIコンテナに任せるのが現在の定番です。なお、シングルトンのBeanは複数のリクエストから同時に使われるため、リクエストごとの値をフィールドに持たないようにします。
Springが自動で使っているパターン
自分でクラスを書かなくても、Springを使うだけで多くのパターンに触れています。仕組みを知っておくと、よくあるつまずきの原因がわかります。
| パターン | Springでの例 | 知っておくと役立つこと |
|---|---|---|
| Proxy | @Transactional、@Cacheable、@Async |
同じクラスの中からメソッドを呼ぶと、プロキシを通らないため効かない |
| Singleton(スコープ) | Beanの標準スコープ | フィールドにリクエストごとの状態を持たない |
| Factory | BeanFactory、FactoryBean |
Beanの生成はコンテナが担当する |
| Observer | ApplicationEventPublisher、@EventListener |
標準は同期実行。非同期にするには @Async などが必要 |
| Chain of Responsibility | Spring Securityの SecurityFilterChain、サーブレットの FilterChain |
フィルターの順番が動作を左右する |
| Adapter | Spring MVCの HandlerAdapter |
形の違うハンドラーを共通の方法で呼び出す |
| Strategy | PasswordEncoder など多くのインターフェース |
実装を差し替えるだけで振る舞いを変えられる |
モダンJavaで変わった書き方
GoFの本は1994年の出版で、当時のC++とSmalltalkを前提にしています。パターンの考え方は今も有効ですが、書き方は言語の進化で簡単になりました。
| パターン | 昔の書き方 | 現在のJavaでの書き方 |
|---|---|---|
| Strategy / Command | インターフェース+実装クラスを毎回作る | ラムダ式やメソッド参照を渡す |
| Observer | java.util.Observable を継承 |
リスナーのリスト+ラムダ式、Springのイベント |
| Singleton | private static のインスタンス+同期処理 |
enum、またはDIコンテナのスコープ |
| Visitor | accept / visit の二重の呼び出し |
sealedインターフェース+switchのパターンマッチング(Java 21) |
| Flyweight | 共有プールを自作 | Integer.valueOf() などが標準で実現 |
| Iterator | 自作のIteratorクラス | 拡張for文、Stream API |
たとえばFlyweightは、Integer のキャッシュとしてJava標準に入っています(Java 21で確認すると、Integer の 127 == 127 は true、128 == 128 は false)。Integer.valueOf() は、標準の設定で-128〜127の値を共有します。ラッパー型の比較に == を使うと、値によって結果が変わるため、比較には equals を使います。
デザインパターンを使うときの注意
| よくある失敗 | 起きること | こうするとよい |
|---|---|---|
| パターンを使うこと自体が目的になる | 小さな処理に、クラスが何個も増える | 困りごとが先、パターンは後。早見表の「困っていること」から選ぶ |
| 将来の変更を想像して、先に抽象化する | 実際には変更されず、読みにくさだけが残る | 同じ変更が2〜3回起きてから導入する |
名前だけパターンにする(XxxFactory の中身がただの new) |
読む人が構造を誤解する | パターン名をクラス名に付けるのは、本当にその形のときだけ |
| Singletonで共有の状態を持つ | テストが不安定になり、並行処理で値が混ざる | 状態を持たない、またはDIコンテナのスコープに任せる |
デザインパターンの一番の価値は「共通の語彙」になることです。レビューで「ここはStrategyにしましょう」と言えば、クラスの形まで一言で伝わります。
よくある質問
Q. 23パターンをすべて覚える必要はありますか? A. ありません。まずはStrategy、Template Method、Builder、Adapter、Decorator、Observerの6つと、Singletonの注意点を押さえれば、実務のコードの多くが読めるようになります。残りは、一覧表で「こういう問題にはこういう形がある」と知っておき、必要になったときに調べれば十分です。
Q. StrategyとTemplate Methodの違いは何ですか? A. どちらも「一部を差し替える」パターンですが、Strategyは部品を外から渡す(組み合わせ)、Template Methodは子クラスで上書きする(継承)という違いがあります。実行時に切り替えたい、組み合わせを増やしたい場合はStrategyが向いています。
Q. DecoratorとProxyの違いは何ですか? A. 形(同じインターフェースで包む)はよく似ています。Decoratorは「機能を追加する」ことが目的で、何重にも重ねて使います。Proxyは「アクセスを制御する」ことが目的で、遅延読み込み、権限チェック、トランザクションの開始などを代理で行います。
まとめ
- デザインパターンは、設計でくり返し現れる問題と解決の形に付けた名前。GoFの23パターンは生成・構造・振る舞いの3分類
- 実務でよく使うのはStrategy、Builder、Adapter、Decorator、Observer、Template Methodなど一部
Comparator=Strategy、java.io=Decorator、Arrays.asList=Adapterのように、Java標準ライブラリはパターンの実例の宝庫- Singletonは状態を持つとテストが不安定になる。「1つだけ」はDIコンテナのスコープに任せる
- Springの
@TransactionalはProxy。同じクラス内からの呼び出しでは効かない - ラムダ式・enum・sealed+switchで、モダンJavaではパターンの書き方が簡単になった
- 困りごとが先、パターンは後。変更が実際に起きてから導入する
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「デザインパターンの使いどころ|GoF23の一覧と実務でよく使う8つ」
株式会社RJCでは、読みやすく変更しやすいコードを目指して、設計の引き出しをプロジェクトの中で仲間と増やしています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。