Java におけるコード進化パターン (Code Evolution Patterns in Java)
asato shimotaki <asatohan at gmail.com>
最終更新日 : 2009/6/21 (2004/4/22 より)
Christopher Alexander, The Nature of Order
はじめに
ソフトウェア進化の現実
どうするか
過去のソフトウェア開発の経験から、ソフトウェアの構造には、似た構造が繰り返し現れることが知られています。それら繰り返し現れる構造は、アーキテクチャパターンやデザインパターンと呼ばれています。
また、ソフトウェアの構造の進化にも繰り返し発生するものがあることが知られています。ソフトウェア構造の改善のために繰り返し起こるパターンは、リファクタリングと呼ばれています。
このドキュメントは、ソフトウェア構造の進化のパターンを特定し、カタログ化することを目的としています。
進化パターンを特定し集めることは重要です。
進化パターンの範囲
進化パターン収集方法
Part 1. 理論
設計者とコード進化
コードと特性
要求を満たす多数のコード
異なるパスのコード進化
意図的なコード進化
設計者の経験に依存するコード進化
設計者に依存するコード進化
コード進化
コード進化のルール
コード進化のパターン
コード進化パス
コード進化パターンのメタモデル
コード進化の分類
機能変化
インタフェース変化
モジュール変化
進化リクエスタとプロバイダ
進化パターン間の関係
コード進化の表現レベル
コード進化のパターン化の課題
コード進化の原理
コード進化の性質
適応
Part 2. カタログ
パターンテンプレート
クラスの追加
タイプ:
before:
after:
public class MyClass { public void myMethod() { System.out.println("MyClass.myMethod()"); } }
参考文献とリソース
パターン関係
進化パス
関連パターン
参考文献とリソース
todo
スーパークラスの導入
タイプ:リファクタリング
before:
public class MyClass { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void myMethod() { System.out.println("MyClass.myMethod()"); } }
public class YourClass { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void yourMethod() { System.out.println("YourClass.yourMethod()"); } }after:
public class SuperClass { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class MyClass extends SuperClass { public void myMethod() { System.out.println("MyClass.myMethod()"); } }
public class YourClass extends SuperClass { public void yourMethod() { System.out.println("YourClass.yourMethod()"); } }
参考文献とリソース
進化パス
関連パターン
参考文献とリソース
todo
サブクラスの追加
タイプ:
構成要素:
before:
public class MySuperClass { }
public class MyClassA extends MySuperClass { }
public class MyClassB extends MySuperClass { }after:
public class MySuperClass { }
public class MyClassA extends MySuperClass { }
public class MyClassB extends MySuperClass { }
public class MyClassC extends MySuperClass { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
メソッド関連
メソッドの追加
タイプ:
before:
public class MyClass { public void methodA() { System.out.println("MyClass.methodA"); } }after:
public class MyClass { public void methodA() { System.out.println("MyClass.methodA"); } public void methodB() { System.out.println("MyClass.methodB"); } }
参考文献とリソース
パターン関係
進化パス
関連パターン
参考文献とリソース
todo
public メソッドの追加
タイプ:
進化タイプ:
前提:public なメソッドを追加できる具象クラスまたは抽象クラスが存在する。
構成要素:
public class Component { public void methodA() { System.out.println("Component.methodA()"); } }after:
public class Component { public void methodA() { System.out.println("Component.methodA()"); } public void methodB() { System.out.println("Component.methodA()"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
参考文献とリソース
その他/疑問
public な具象メソッドの追加
タイプ:
進化タイプ:
前提:public な具象メソッドを追加できるクラスが存在する。
構成要素:
public class Component { public void methodA() { System.out.println("Component.methodA()"); } }after:
public class Component { public void methodA() { System.out.println("Component.methodA()"); } public void methodB() { System.out.println("Component.methodB()"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
private メソッドの追加
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { public void m() { System.out.println("Component method"); } }after:
public class Component { public void m() { privateMethod(); } private void privateMethod() { System.out.println("Component method"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
static メソッドの追加
タイプ:
before:
public class UtilClass { public static void myStaticMethodA() { System.out.println("UtilClass - myStaticMethodA"); } }after:
public class UtilClass { public static void myStaticMethodA() { System.out.println("UtilClass - myStaticMethodA"); } public static void myStaticMethodB() { System.out.println("UtilClass - myStaticMethodB"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
get method の追加
タイプ:
before:
public class MyClass { public void method() { System.out.println("MyClass.method()"); } }after:
public class MyClass { private String name; public MyClass(String name) { this.name = name; } public void method() { System.out.println("MyClass.method()"); } public String getName() { return name; } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
set method の追加
タイプ:
before:
public class MyClass { private String name; public MyClass(String name) { this.name = name; } public void method() { System.out.println("MyClass.method()"); } public String getName() { return name; } }after:
public class MyClass { private String name; public MyClass(String name) { this.name = name; } public void method() { System.out.println("MyClass.method()"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Type アノテーションの追加
タイプ:
before:
after:
import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.ElementType; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotation { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Interface へのメソッドの追加
タイプ:
構成要素:
public interface MyInterface { public void methodA(); }
public class MyInterfaceImpl implements MyInterface { public void methodA() { System.out.println("MyInterfaceImpl.methodA()"); } }after:
public interface MyInterface { public void methodA(); public void methodB(); }
public class MyInterfaceImpl implements MyInterface { public void methodA() { System.out.println("MyInterfaceImpl.methodA()"); } public void methodB() { System.out.println("MyInterfaceImpl.methodB()"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Method アノテーションの追加
タイプ:
before:
after:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyMethodAnnotation { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
ランタイム例外の追加
タイプ:
before:
after:
public class MyRuntimeException extends RuntimeException { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Field アノテーションの追加
タイプ:
before:
after:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface MyFieldAnnotation { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
フィールドアクセスのための get method の追加
タイプ:拡張
前提:
before:
public class Component { private String name; public Component(String name) { this.name = name; } public void outputName() { System.out.println("name = " + name); } public void setName(String name) { this.name = name; } }after:
public class EvolutionRequester { private Component comp; public EvolutionRequester(Component comp) { this.comp = comp; } public void method() { System.out.println("*** " + comp.getName() + " ***"); } }
public class Component { private String name; public Component(String name) { this.name = name; } public void outputName() { System.out.println("name = " + name); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
オーバーロードメソッドの追加
タイプ:
before:
public class Outputter { public void output(String str) { System.out.println(str); } }after:
public class Outputter { public void output(String str) { System.out.println(str); } public void output(int i) { System.out.println(i); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
フィールド更新のための set method の追加
タイプ:
before:
public class MyClass { private String name; public MyClass(String name) { this.name = name; } public String getName() { return name; } }after:
public class MyClass { private String name; public MyClass(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
interface の追加
タイプ:
before:
after:
public interface MyInterface { public void method(); }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
interface の実装
タイプ:
before:
public interface MyInterface { public void method(); }
public class MyClass { public void method() { System.out.println("MyClass.method()"); } }after:
public class MyClass implements MyInterface { public void method() { System.out.println("MyClass.method()"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
コレクションフィールドアクセスのための get method の追加
タイプ:
before:
public class Item { }
public class ItemContainer { private Listafter:- items = new ArrayList
- (); public void addItem(Item item) { items.add(item); } }
public class Item { }
public class ItemContainer { private List- items = new ArrayList
- (); public void addItem(Item item) { items.add(item); } public Item[] getItems() { return items.toArray( new Item[items.size()] ); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
forwarding method(転送メソッド)の追加
タイプ:
before:
public class MyClass { private ForwardedClass forwarded = new ForwardedClass(); public void myMethod() { System.out.println("MyClass.myMethod()"); } }
public class ForwardedClass { public void method() { System.out.println("ForwardedClass.method()"); } }after:
public class MyClass { private ForwardedClass forwarded = new ForwardedClass(); public void myMethod() { System.out.println("MyClass.myMethod()"); } public void method() { // 転送メソッド forwarded.method(); } }
public class ForwardedClass { public void method() { System.out.println("ForwardedClass.method()"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象クラス継承によるクラスの追加
タイプ:
before:
public abstract class MyAbstractClass { public abstract void abstractMethod(); public void method() { System.out.println("MyAbstractClass.method()"); } }after:
public abstract class MyAbstractClass { public abstract void abstractMethod(); public void method() { System.out.println("MyAbstractClass.method()"); } }
public class MyClass extends MyAbstractClass { @Override public void abstractMethod() { System.out.println("MyClass.abstractMethod()"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
リファクタリング時におけるフィールドアクセスのための get method の追加
タイプ:リファクタリング
前提:
before:
public class MyClass { private String str; public MyClass(String str) { this.str = str; } public void print() { System.out.println("str = " + str); } }after:
public class MyClass { private String str; public MyClass(String str) { this.str = str; } public void print() { System.out.println("str = " + str); } public String getStr() { return str; } }
public class MyClient { public void method(MyClass my) { System.out.println( "my.getStr() = " + my.getStr() ); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
interface の継承
タイプ:拡張
前提:
before:
public interface SomeInterface { public void someMethod(); }
public interface MyInterface { public void myMethod(); }
public class MyClass implements MyInterface { public void myMethod() { } }after:
public interface SomeInterface { public void someMethod(); }
public interface MyInterface extends SomeInterface { public void myMethod(); }
public class MyClass implements MyInterface { public void myMethod() { } public void someMethod() { } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
setter/getter の追加
タイプ:拡張
前提:
before:
public class Component { }after:
public class Component { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class EvolutionRequester { public void editName(Component comp) { String old = comp.getName(); comp.setName("*** " + old + " ***"); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
interface におけるメソッドの置き換え
タイプ:
前提:
before:
public interface Component { public String getName(); }
public class MyComponent implements Component { private String name; public MyComponent(String name) { this.name = name; } public String getName() { return name; } }
public class Main { public static void main(String[] args) { printName( new MyComponent("aaa") ); } private static void printName(Component comp) { System.out.println("name : " + comp.getName()); } }after:
public class Name { private String name; public Name(String name) { this.name = name; } public String getName() { return name; } }
public interface Component { public Name getName(); }
public class MyComponent implements Component { private Name name; public MyComponent(Name name) { this.name = name; } public Name getName() { return name; } }
public class Main { public static void main(String[] args) { printName( new MyComponent( new Name("aaa") ) ); } private static void printName(Component comp) { System.out.println("name : " + comp.getName().getName()); } }
参考文献とリソース
例
import java.awt.image.BufferedImage; public interface Player extends MapCharactor { public int getHP(); public void setHP(int hp); public int getMaxHP(); public void setMaxHP(int maxhp); public void setImage(BufferedImage image); public BufferedImage getImage(); }
public class MainPanel extends JPanel implements Runnable { // ... 省略 private void drawPlayer(Player player) { // ... 省略 dbg.drawImage(player.getAnimationImage().getImage(), x, y, null); } }after:
public interface Player extends MapCharactor { public int getHP(); public void setHP(int hp); public int getMaxHP(); public void setMaxHP(int maxhp); public void setAnimationImage(AnimationImage image); public AnimationImage getAnimationImage(); }
public class MainPanel extends JPanel implements Runnable { // ... 省略 private void drawPlayer(Player player) { // ... 省略 dbg.drawImage(player.getAnimationImage().getImage(), x, y, null); } }
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
クラス階層の追加
タイプ:
前提:
before:
public class Component { public void method() { // ... } }after:
public class Component { public void method() { // ... MyComponentInterface comp = new MyComponent(); comp.method(); } }
public interface MyComponentInterface { public void method(); }
public class MyComponent implements MyComponentInterface { public void method() { System.out.println("MyComponent.method()"); } }
参考文献とリソース
議論
MyComponent comp = new MyComponent();とせずに
MyComponentInterface comp = new MyComponent();としています。
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象クラスの継承によるコードの重複の削除
タイプ:リファクタリング時
前提:抽象クラスが存在する。クラスが存在する。
before:
public class ConcreteComponentA { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void methoA() { } }
public abstract class AbstractComponent { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class ConcreteComponentB extends AbstractComponent { public void methodB() { } }after:
public abstract class AbstractComponent { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class ConcreteComponentA extends AbstractComponent { public void methoA() { } }
public class ConcreteComponentB extends AbstractComponent { public void methodB() { } }
参考文献とリソース
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象クラスへの具象メソッドの追加
タイプ:
進化タイプ:
前提:抽象クラスが存在する。
構成要素:
public abstract class AbstractClass { public abstract void abstractMethod(); public void methodA() { System.out.println("AbstractClass.methodA() "); } }after:
public abstract class AbstractClass { public abstract void abstractMethod(); public void methodA() { System.out.println("AbstractClass.methodA() "); } public void methodB() { System.out.println("AbstractClass.methodB() "); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
抽象クラスへの抽象メソッドの追加
タイプ:
前提:抽象クラスが存在する。
before:
public abstract class AbstractClass { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public abstract void abstractMethod1(); }
public class ConcreteClassA extends AbstractClass { @Override public void abstractMethod1() { System.out.println("ConcreteClassA.abstractMethod1()"); } }
public class ConcreteClassB extends AbstractClass { @Override public void abstractMethod1() { System.out.println("ConcreteClassB.abstractMethod1()"); } }after:
public abstract class AbstractClass { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public abstract void abstractMethod1(); public abstract void abstractMethod2(); }
public class ConcreteClassA extends AbstractClass { @Override public void abstractMethod1() { System.out.println("ConcreteClassA.abstractMethod1()"); } @Override public void abstractMethod2() { System.out.println("ConcreteClassA.abstractMethod2()"); } }
public class ConcreteClassB extends AbstractClass { @Override public void abstractMethod1() { System.out.println("ConcreteClassB.abstractMethod1()"); } @Override public void abstractMethod2() { System.out.println("ConcreteClassB.abstractMethod2()"); } }
参考文献とリソース
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象クラスへの具象メソッドの引き上げ
タイプ:
進化タイプ:
前提:具象クラスと抽象クラスの間に継承関係がある。
構成要素:
public abstract class AbstractClass { public void method() { System.out.println("method"); } public abstract void abstractMethod(); }
public class ConcreteClass extends AbstractClass { public void concreteMethod() { System.out.println("concreteMethod"); } @Override public void abstractMethod() { System.out.println("abstractMethod"); } }after:
public abstract class AbstractClass { public void method() { System.out.println("method"); } public abstract void abstractMethod(); public void concreteMethod() { System.out.println("concreteMethod"); } }
public class ConcreteClass extends AbstractClass { @Override public void abstractMethod() { System.out.println("abstractMethod"); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
抽象クラスのジェネリック化
タイプ:リファクタリング
進化タイプ:
前提:
before:
public class Component { public void componentMethod() { System.out.println("Component.componentMethod()"); } }
public class SubComponentA extends Component { public void subMethodA() { System.out.println("SubComponentA.subMethodA()"); } }
public class SubComponentB extends Component { public void subMethodB() { System.out.println("SubComponentB.subMethodB()"); } }
public abstract class AbstractClass { private Component component; public AbstractClass(Component component) { this.component = component; } public void method() { component.componentMethod(); } }
public class ConcreteClassA extends AbstractClass { private SubComponentA component; public ConcreteClassA(SubComponentA component) { super(component); this.component = component; } public void methodA() { component.subMethodA(); } }
public class ConcreteClassB extends AbstractClass { private SubComponentB component; public ConcreteClassB(SubComponentB component) { super(component); this.component = component; } public void methodB() { component.subMethodB(); } }after:
public class Component { // 変更なし public void componentMethod() { System.out.println("Component.componentMethod()"); } }
public class SubComponentA extends Component { // 変更なし public void subMethodA() { System.out.println("SubComponentA.subMethodA()"); } }
public class SubComponentB extends Component { // 変更なし public void subMethodB() { System.out.println("SubComponentB.subMethodB()"); } }
public abstract class AbstractClass<T extends Component> { // ジェネリック化 protected T component; public AbstractClass(T component) { this.component = component; } public void method() { component.componentMethod(); } }
public class ConcreteClassA extends AbstractClass<SubComponentA> { public ConcreteClassA(SubComponentA comp) { super(comp); } public void methodA() { component.subMethodA(); } }
public class ConcreteClassB extends AbstractClass<SubComponentB> { public ConcreteClassB(SubComponentB comp) { super(comp); } public void methodB() { component.subMethodB(); } }
参考文献とリソース
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
トップレベル interface の追加
タイプ:
進化タイプ:
前提:
before:
public abstract class AbstractClass { public void commonMethod() { System.out.println("AbstractClass.commonMethod()"); } public abstract void specificMethod(); }
public class ConcreteClassA extends AbstractClass { @Override public void specificMethod() { System.out.println("ConcreteClassA.specificMethod()"); } }
public class ConcreteClassB extends AbstractClass { @Override public void specificMethod() { System.out.println("ConcreteClassB.specificMethod()"); } }after:
public interface Interface { public void commonMethod(); public void specificMethod(); }
public abstract class AbstractClass implements Interface { public void commonMethod() { System.out.println("AbstractClass.commonMethod()"); } public abstract void specificMethod(); }
public class ConcreteClassA extends AbstractClass { @Override public void specificMethod() { System.out.println("ConcreteClassA.specificMethod()"); } }
public class ConcreteClassB extends AbstractClass { @Override public void specificMethod() { System.out.println("ConcreteClassB.specificMethod()"); } }
参考文献とリソース
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
列挙型への定数の追加
タイプ:
進化タイプ:
前提:
before:
public enum EnumType { TypeA, TypeB }after:
public enum EnumType { TypeA, TypeB, TypeC }
参考文献とリソース
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
コンストラクタへのパラメータの追加
タイプ:
進化タイプ:
前提:
before:
public class MyClass { private int i; public MyClass(int i) { this.i = i; } public void method() { System.out.println(i); } }after:
public class MyClass { private int i; private int j; public MyClass(int i, int j) { this.i = i; this.j = j; } public void method() { System.out.println(i); System.out.println(j); } }
参考文献とリソース
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
todo
フィールドの削除
タイプ:
進化タイプ:
前提:
before:
public class MyClass { private String s; }after:
public class MyClass { }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
getter/setter の移動
タイプ:
進化タイプ:
前提:
構成要素:
public class ComponentA { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class ComponentB { }after:
public class ComponentA { }
public class ComponentB { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
Interface Adapter の導入
タイプ:
進化タイプ:
前提:
構成要素:
public interface MyInterface { public void methodA(); public void methodB(); }
public class MyClassA implements MyInterface { @Override public void methodA() { System.out.println("MyClassA.methodA()"); } @Override public void methodB() { } // 何もしない }
public class MyClassB implements MyInterface { @Override public void methodA() { } // 何もしない @Override public void methodB() { System.out.println("MyClassB.methodB()"); } }after:
public interface MyInterface { // 変更なし public void methodA(); public void methodB(); }
public abstract class MyInterfaceAdapter implements MyInterface { public void methodA() { } public void methodB() { } }
public class MyClassA extends MyInterfaceAdapter { @Override public void methodA() { System.out.println("MyClassA.methodA()"); } }
public class MyClassB extends MyInterfaceAdapter { @Override public void methodB() { System.out.println("MyClassA.methodB()"); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
interface のジェネリック化
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { }
public class SubComponentA extends Component { }
public class SubComponentB extends Component { }
public interface MyInterface { public void setComponent(Component c); public Component getComponent(); }after:
public class Component { // 変更無し }
public class SubComponentA extends Component { // 変更無し }
public class SubComponentB extends Component { // 変更無し }
public interface MyInterface<T extends Component> { public void setComponent(T c); public T getComponent(); }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
Java 基本関連 - メソッド関連 - メソッドボディ関連
メソッドボディの変更
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { public void method() { System.out.println("method"); } }after:
public class Component { public void method() { System.out.println("new code"); // 変更部分 System.out.println("method"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public メソッドのボディの変更
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { public void method() { System.out.println("method"); } }after:
public class Component { public void method() { System.out.println("new code"); // 変更部分 System.out.println("method"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
コンストラクタへのパラメータの追加によるメソッドボディの変更
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { private String param1; private String param2; public Component(String param1, String param2) { this.param1 = param1; this.param2 = param2; } public String getParam1() { return param1; } public String getParam2() { return param2; } }
public class ComponentClient { public void method() { Component comp = new Component("aaa", "bbb"); System.out.println( comp.getParam1() ); System.out.println( comp.getParam2() ); } }after:
public class Component { private String param1; private String param2; private String param3; public Component(String param1, String param2, String param3) { // コンストラクタへのパラメータの追加 this.param1 = param1; this.param2 = param2; this.param3 = param3; } public String getParam1() { return param1; } public String getParam2() { return param2; } public String getParam3() { return param3; } }
public class ComponentClient { public void method() { Component comp = new Component("aaa", "bbb", "ccc"); System.out.println( comp.getParam1() ); System.out.println( comp.getParam2() ); System.out.println( comp.getParam3() ); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
Java 関連 - Event Listener 関連
EventListener の導入
タイプ:
進化タイプ:
前提:
before:
public class Comonent { public void method() { runEvent(); } private void runEvent() { System.out.println("event"); } }
public class Main { public static void main(String[] args) { Comonent p = new Comonent(); p.method(); } }実行結果:
eventafter:
public class ComponentEvent { }
public interface ComponentEventListener { public void eventStarted(ComponentEvent e); public void eventFinished(ComponentEvent e); }
public class ComponentEventListenerImpl implements ComponentEventListener { public void eventStarted(ComponentEvent e) { System.out.println("started"); } public void eventFinished(ComponentEvent e) { System.out.println("finished"); } }
public class Comonent { private List listeners = new ArrayList(); public void addEventListener(ComponentEventListener l) { this.listeners.add(l); } public void removeEventListener(ComponentEventListener l) { this.listeners.add(l); } private void fireEventStarted() { ComponentEvent e = new ComponentEvent(); for(Iterator itr = listeners.iterator(); itr.hasNext();) { ComponentEventListener l = (ComponentEventListener)itr.next(); l.eventStarted(e); } } private void fireEventFinished() { ComponentEvent e = new ComponentEvent(); for(Iterator itr = listeners.iterator(); itr.hasNext();) { ComponentEventListener l = (ComponentEventListener)itr.next(); l.eventFinished(e); } } public void method() { fireEventStarted(); runEvent(); fireEventFinished(); } private void runEvent() { System.out.println("event"); } }
public class Main { public static void main(String[] args) { Comonent p = new Comonent(); p.addEventListener( new ComponentEventListenerImpl() ); p.method(); } }実行結果:
started event finished
EventListener の導入2
タイプ:リファクタリング
進化タイプ:
前提:
before:
public class Component { private int data; public void setData(int data) { this.data = data; } public int getData() { return data; } }
public class ComponentClient { private Component component; public ComponentClient(Component component) { this.component = component; } public void method() { System.out.println("action"); component.setData(10); } }
public class Main { public static void main(String[] args) { Component comp = new Component(); ComponentClient client = new ComponentClient(comp); client.method(); } }after:
public interface ComponentListener { public void dataChanged(ComponentEvent e); }
public class ComponentDataChangedAction implements ComponentListener { @Override public void dataChanged(ComponentEvent e) { System.out.println("action"); } }
public class ComponentEvent { private Component comp; public ComponentEvent(Component comp) { this.comp = comp; } public Component getComponent() { return comp; } }
public class Component { private int data; private List<ComponentListener> listeners = new ArrayList<ComponentListener>(); public void addComponentListener(ComponentListener l) { listeners.add(l); } public void setData(int data) { this.data = data; // private or protected メソッドにリファクタリングしてもよい for(ComponentListener l: listeners) { l.dataChanged(new ComponentEvent(this)); } } public int getData() { return data; } }
public class ComponentClient { private Component component; public ComponentClient(Component component) { this.component = component; } public void method() { component.setData(10); } }
public class Main { public static void main(String[] args) { Component comp = new Component(); comp.addComponentListener( new ComponentDataChangedAction() ); ComponentClient client = new ComponentClient(comp); client.method(); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
EventListener の導入 - パラメータの追加
public interface ComponentListener { // Listener public void myMethodExecuted(Class type); // eventPerformed(Type param1) }
public class Component { private ComponentListener listener = new ComponentListener() { public void myMethodExecuted(Class type) { } }; public void myMethod() { listener.myMethodExecuted( getClass() ); System.out.println("Component.myMethod()"); } }
public class Main { public static void main(String[] args) { Component comp = new Component(); comp.myMethod(); } }after:
public interface ComponentListener { // Listener public void myMethodExecuted(Class type, String methodName); // eventPerformed(Type param1, Type param2) }
public class Component { private ComponentListener listener = new ComponentListener() { public void myMethodExecuted(Class type, String methodName) { } }; public void myMethod() { listener.myMethodExecuted( getClass(), "myMethod"); System.out.println("Component.myMethod()"); } }
public class Main { public static void main(String[] args) { Component comp = new Component(); comp.myMethod(); } }
EventListener の導入 - イベントの追加
public interface ComponentListener { public void myMethodExecuted(Class type); }
public class Component { private ComponentListener listener = new ComponentListener() { public void myMethodExecuted(Class type) { } }; public void setComponentListener(ComponentListener listener) { this.listener = listener; } public void myMethod() { listener.myMethodExecuted( getClass() ); System.out.println("Component.myMethod()"); } }after:
public interface ComponentListener { public void myMethodExecuted(Class type); public void yourMethodExecuted(Class type); }
public class Component { private ComponentListener listener = new ComponentListener() { public void myMethodExecuted(Class type) { } public void yourMethodExecuted(Class type) { } }; public void setComponentListener(ComponentListener listener) { this.listener = listener; } public void myMethod() { listener.myMethodExecuted( getClass() ); System.out.println("Component.myMethod()"); } public void yourMethod() { listener.yourMethodExecuted( getClass() ); System.out.println("Component.yourMethod()"); } }
Event Listener の導入 - Event の追加2
タイプ:
before:
public class Event { }
public interface EventListener { public void eventAOccured(Event event); public void eventBOccured(Event event); }
public class EventSource { private List listeners = new ArrayList(); public void addEventListener(EventListener l) { listeners.add(l); } public void method() { fireEventAOccured( new Event() ); // ... fireEventBOccured( new Event() ); } private void fireEventAOccured(Event event) { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (EventListener)itr.next() ).eventAOccured(event); } } private void fireEventBOccured(Event event) { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (EventListener)itr.next() ).eventBOccured(event); } } }after:
public class Event { }
public interface EventListener { public void eventAOccured(Event event); public void eventBOccured(Event event); public void eventCOccured(Event event); }
public class EventSource { private List listeners = new ArrayList(); public void addEventListener(EventListener l) { listeners.add(l); } public void method() { fireEventAOccured( new Event() ); // ... fireEventBOccured( new Event() ); // ... fireEventCOccured( new Event() ); } private void fireEventAOccured(Event event) { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (EventListener)itr.next() ).eventAOccured(event); } } private void fireEventBOccured(Event event) { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (EventListener)itr.next() ).eventBOccured(event); } } private void fireEventCOccured(Event event) { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (EventListener)itr.next() ).eventCOccured(event); } } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
ConcreteListener の追加
タイプ:
進化タイプ:
前提:
構成要素:
public class ComponentEvent { private String contextInfo1; private String contextInfo2; public ComponentEvent(String contextInfo1, String contextInfo2) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListenerA implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println("ConcreteComponentListenerA - " + e.getContextInfo1() ); } }
public class Component { private Listafter:listeners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
public class ComponentEvent { private String contextInfo1; private String contextInfo2; public ComponentEvent(String contextInfo1, String contextInfo2) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListenerA implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println("ConcreteComponentListenerA - " + e.getContextInfo1() ); } }
public class ConcreteComponentListenerB implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println("ConcreteComponentListenerB - " + e.getContextInfo2() ); } }
public class Component { private Listlisteners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
EventListener の導入 - Null Listener の導入
public interface ComponentListener { public void methodExecuted(String methodName); }
public class Component { private ComponentListener listener = new ComponentListener() { public void methodExecuted(String methodName) { } }; public void myMethod() { listener.methodExecuted("myMethod"); System.out.println("Component.myMethod()"); } public void setComponentListener(ComponentListener listener) { this.listener = listener; } }after:
public interface ComponentListener { public void methodExecuted(String methodName); }
public class NullComponentListener implements ComponentListener { public void methodExecuted(String methodName) { } }
public class Component { private ComponentListener listener = new NullComponentListener(); public void myMethod() { listener.methodExecuted("myMethod"); System.out.println("Component.myMethod()"); } public void setComponentListener(ComponentListener listener) { this.listener = listener; } }
EventListener の導入 - Listener Method の追加
public interface ComponentListener { public void beforeMyMethodExecution(); }
public class ConcreteComponentListener implements ComponentListener { public void beforeMyMethodExecution() { System.out.println("ConcreteComponentListener.beforeMyMethodExecution()"); } }
public class Component { private ComponentListener listener = new ComponentListener() { public void beforeMyMethodExecution() { } }; public void myMethod() { listener.beforeMyMethodExecution(); System.out.println("Component.myMethod()"); } public void setComponentListener(ComponentListener listener) { this.listener = listener; } }after:
public interface ComponentListener { public void beforeMyMethodExecution(); public void afterMyMethodExecution(); }
public class ConcreteComponentListener implements ComponentListener { public void beforeMyMethodExecution() { System.out.println("ConcreteComponentListener.beforeMyMethodExecution()"); } public void afterMyMethodExecution() { System.out.println("ConcreteComponentListener.afterMyMethodExecution()"); } }
public class Component { private ComponentListener listener = new ComponentListener() { public void beforeMyMethodExecution() { } public void afterMyMethodExecution() { } }; public void myMethod() { listener.beforeMyMethodExecution(); System.out.println("Component.myMethod()"); listener.afterMyMethodExecution(); } public void setComponentListener(ComponentListener listener) { this.listener = listener; } }
進化パスと関連パターン
参考文献とリソース
todo
Event Object への get method の追加
タイプ:
進化タイプ:メソッドの追加
前提:Event Listener パターンが適用されている。Event Object が存在する。
before:
public class ComponentEvent { private String eventInfo1; public ComponentEvent(String eventInfo1) { this.eventInfo1 = eventInfo1; } public String getEventInfo1() { return eventInfo1; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class MyComponentListenerA implements ComponentListener { public void eventOccurred(ComponentEvent e) { System.out.println("event info1: " + e.getEventInfo1() ); } }
public class Component { private Listlisteners = new ArrayList (); public void addComponentListener(ComponentListener l) { listeners.add(l); } public void method() { System.out.println("before evnet"); fireEventOccurred( new ComponentEvent("aaa") ); System.out.println("after evnet"); } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
public class Main { public static void main(String[] args) { Component comp = new Component(); comp.addComponentListener( new MyComponentListenerA() ); comp.method(); } }実行結果:
before evnet event info1: aaa after evnetafter:
public class ComponentEvent { private String eventInfo1; private int eventInfo2; public ComponentEvent(String eventInfo1, int eventInfo2) { this.eventInfo1 = eventInfo1; this.eventInfo2 = eventInfo2; } public String getEventInfo1() { return eventInfo1; } public int getEventInfo2() { return eventInfo2; } }
public interface ComponentListener { // 変更なし public void eventOccurred(ComponentEvent e); }
public class MyComponentListenerA implements ComponentListener { // 変更なし public void eventOccurred(ComponentEvent e) { System.out.println("event info1: " + e.getEventInfo1() ); } }
public class MyComponentListenerB implements ComponentListener { // 新規追加 public void eventOccurred(ComponentEvent e) { System.out.println("event info2: " + e.getEventInfo2() ); } }
public class Component { private Listlisteners = new ArrayList (); public void addComponentListener(ComponentListener l) { listeners.add(l); } public void method() { System.out.println("before evnet"); fireEventOccurred( new ComponentEvent("aaa", 111) ); System.out.println("after evnet"); } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
public class Main { public static void main(String[] args) { Component comp = new Component(); comp.addComponentListener( new MyComponentListenerA() ); comp.addComponentListener( new MyComponentListenerB() ); comp.method(); } }実行結果:
before evnet event info1: aaa event info2: 111 after evnet
参考文献とリソース
進化リクエスタ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
EventObject のコンストラクタへのパラメータの追加
タイプ:
進化タイプ:
前提:
構成要素:
public class ComponentEvent { private String contextInfo1; private String contextInfo2; public ComponentEvent(String contextInfo1, String contextInfo2) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListener implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println( e.getContextInfo1() ); System.out.println( e.getContextInfo2() ); } }
public class Component { private Listafter:listeners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
public class ComponentEvent { private String contextInfo1; private String contextInfo2; private String contextInfo3; public ComponentEvent(String contextInfo1, String contextInfo2, String contextInfo3) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; this.contextInfo3 = contextInfo3; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListener implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println( e.getContextInfo1() ); System.out.println( e.getContextInfo2() ); } }
public class Component { private Listlisteners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; String eventContextInfo3 = "eventContextInfo3"; // ... 何らかの処理 fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2, eventContextInfo3) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
event handler メソッドの実装
タイプ:
進化タイプ:
前提:具体的な処理が記述されていない event handler メソッドが存在する。
構成要素:
public class ComponentEvent { private String contextInfo1; private String contextInfo2; public ComponentEvent(String contextInfo1, String contextInfo2) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventAOccurred(ComponentEvent e); public void eventBOccurred(ComponentEvent e); }
public class ConcreteComponentListenerA implements ComponentListener { @Override public void eventAOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerA.eventAOccurred" ); } @Override public void eventBOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerA.eventBOccurred" ); } }
public class ConcreteComponentListenerB implements ComponentListener { @Override public void eventAOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerB.eventAOccurred" ); } @Override public void eventBOccurred(ComponentEvent e) { // このイベントには対応しない } }
public class Component { private Listafter:listeners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 fireEventAOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 fireEventBOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventAOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventAOccurred(e); } } private void fireEventBOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventBOccurred(e); } } }
public class ComponentEvent { // 変更なし private String contextInfo1; private String contextInfo2; public ComponentEvent(String contextInfo1, String contextInfo2) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { // 変更なし public void eventAOccurred(ComponentEvent e); public void eventBOccurred(ComponentEvent e); }
public class ConcreteComponentListenerA implements ComponentListener { // 変更なし @Override public void eventAOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerA.eventAOccurred" ); } @Override public void eventBOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerA.eventBOccurred" ); } }
public class ConcreteComponentListenerB implements ComponentListener { @Override public void eventAOccurred(ComponentEvent e) { System.out.println( "ConcreteComponentListenerB.eventAOccurred" ); } @Override public void eventBOccurred(ComponentEvent e) { // このイベントには対応するように変更 System.out.println( "ConcreteComponentListenerB.eventAOccurred" ); } }
public class Component { // 変更なし private Listlisteners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 fireEventAOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 fireEventBOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventAOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventAOccurred(e); } } private void fireEventBOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventBOccurred(e); } } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
EventObject のコンストラクタへのパラメータの追加による Event Source のメソッドボディの変更
タイプ:
進化タイプ:
前提:
構成要素:
public class ComponentEvent { private String contextInfo1; private String contextInfo2; // Event Object のコンストラクタへのパラメータの追加 public ComponentEvent(String contextInfo1, String contextInfo2, String contextInfo3) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListener implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println( e.getContextInfo1() ); System.out.println( e.getContextInfo2() ); } }
public class Component { private Listafter:listeners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; // ... 何らかの処理 // コンパイルエラー fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
public class ComponentEvent { private String contextInfo1; private String contextInfo2; // Event Object のコンストラクタへのパラメータの追加 public ComponentEvent(String contextInfo1, String contextInfo2, String contextInfo3) { this.contextInfo1 = contextInfo1; this.contextInfo2 = contextInfo2; } public String getContextInfo1() { return contextInfo1; } public String getContextInfo2() { return contextInfo2; } }
public interface ComponentListener { public void eventOccurred(ComponentEvent e); }
public class ConcreteComponentListener implements ComponentListener { @Override public void eventOccurred(ComponentEvent e) { System.out.println( e.getContextInfo1() ); System.out.println( e.getContextInfo2() ); } }
public class Component { private Listlisteners = new ArrayList (); public void addListener(ComponentListener l) { listeners.add(l); } public void method() { String eventContextInfo1 = "eventContextInfo1"; String eventContextInfo2 = "eventContextInfo2"; String eventContextInfo3 = "eventContextInfo3"; // ... 何らかの処理 fireEventOccurred( new ComponentEvent(eventContextInfo1, eventContextInfo2, eventContextInfo3) ); // ... 何らかの処理 } private void fireEventOccurred(ComponentEvent e) { for(ComponentListener l : listeners) { l.eventOccurred(e); } } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
Listener interface の implements
タイプ:
before:
public class MyClass { public void myMethod() { System.out.println("MyClass.myMethod()"); } }
public interface ComponentListener { public void methodInvoked(Component comp); }
public class Component { private List listeners = new ArrayList(); public void addListener(ComponentListener listener) { listeners.add(listener); } public void removeListener(ComponentListener listener) { listeners.remove(listener); } private void fireMethodInvoked() { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (ComponentListener)itr.next() ).methodInvoked(this); } } public void method() { fireMethodInvoked(); System.out.println("Component.method()"); } }after:
public class MyClass implements ComponentListener { public void methodInvoked(Component comp) { } public void myMethod() { System.out.println("MyClass.myMethod()"); } }
public interface ComponentListener { // 変更なし public void methodInvoked(Component comp); }
public class Component { // 変更なし private List listeners = new ArrayList(); public void addListener(ComponentListener listener) { listeners.add(listener); } public void removeListener(ComponentListener listener) { listeners.remove(listener); } private void fireMethodInvoked() { for(Iterator itr = listeners.iterator(); itr.hasNext();) { ( (ComponentListener)itr.next() ).methodInvoked(this); } } public void method() { fireMethodInvoked(); System.out.println("Component.method()"); } }
参考文献とリソース
進化パス
関連パターン
参考文献とリソース
todo
ElementType の導入
public interface Element { }
public class ConcreteElementA implements Element { }
public class ConcreteElementB implements Element { }after:
public class ElementType { public static final ElementType ELEMENT_A = new ElementType(); public static final ElementType ELEMENT_B = new ElementType(); private ElementType() { } }
public interface Element { public ElementType getType(); }
public class ConcreteElementA implements Element { public ElementType getType() { return ElementType.ELEMENT_A; } }
public class ConcreteElementB implements Element { public ElementType getType() { return ElementType.ELEMENT_B; } }
インタフェースの実装 + DI
public class MyConcreteClass { public void methodA() { } public void methodB() { } public void methodC() { } }
public class Main { public static void main(String[] args) { MyConcreteClass my = new MyConcreteClass(); my.methodA(); } }after:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="my" class="evo.impl_inter.MyConcreteClass"/> </beans>
public interface MyInterface { public void methodA(); }
public class MyConcreteClass implements MyInterface { public void methodA() { } public void methodB() { } public void methodC() { } }
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { BeanFactory factory = new ClassPathXmlApplicationContext("bean.xml"); MyInterface my = (MyInterface)factory.getBean("my"); my.methodA(); } }
参考文献とリソース
todo
Preprocess Command Executor の導入
before:
public class Data { // データを編集する適当なメソッド }
public class ConcretePreprocessCommandA { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandA - param = " + param); } }
public class ConcretePreprocessCommandB { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandB - param = " + param); } }
public class ConcretePreprocessCommandC { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandC - param = " + param); } }
public class Main { public static void main(String[] args) { Data data = new Data(); ConcretePreprocessCommandA commA = new ConcretePreprocessCommandA(); commA.setParam("aaa"); commA.execute(data); ConcretePreprocessCommandB commB = new ConcretePreprocessCommandB(); commB.setParam("bbb"); commB.execute(data); ConcretePreprocessCommandC commC = new ConcretePreprocessCommandC(); commC.setParam("ccc"); commC.execute(data); } }after:
public class Data { // データを編集する適当なメソッド }
public interface PreprocessCommand { public void execute(Data data); }
public class ConcretePreprocessCommandA implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandA - param = " + param); } }
public class ConcretePreprocessCommandB implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandB - param = " + param); } }
public class ConcretePreprocessCommandC implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandC - param = " + param); } }
public class PreprocessCommandExecutor { private List commands = new ArrayList(); public void addCommand(PreprocessCommand command) { commands.add(command); } public void execute(Data data) { for(Iterator itr = commands.iterator(); itr.hasNext(); ) { ( (PreprocessCommand)itr.next() ).execute(data); } } }
public class Main { public static void main(String[] args) { Data data = new Data(); ConcretePreprocessCommandA commA = new ConcretePreprocessCommandA(); commA.setParam("aaa"); ConcretePreprocessCommandB commB = new ConcretePreprocessCommandB(); commB.setParam("bbb"); ConcretePreprocessCommandC commC = new ConcretePreprocessCommandC(); commC.setParam("ccc"); PreprocessCommandExecutor executor = new PreprocessCommandExecutor(); executor.addCommand(commA); executor.addCommand(commB); executor.addCommand(commC); executor.execute(data); } }
進化パス
関連パターン
参考文献とリソース
todo
TestCase の追加
タイプ:
before:
public class Item { private String name; public Item(String name) { this.name = name; } }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public void removeItem(Item item) { items.remove(item); } public boolean contains(Item item) { return items.contains(item); } }after:
public class Item { private String name; public Item(String name) { this.name = name; } }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public void removeItem(Item item) { items.remove(item); } public boolean contains(Item item) { return items.contains(item); } }
public class ItemContainerTest extends TestCase { public void test() { Item item = new Item("aaa"); ItemContainer container = new ItemContainer(); container.addItem(item); assertTrue(container.contains(item)); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Test Method の追加
タイプ:
before:
public class Item { private String name; public Item(String name) { this.name = name; } }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public void removeItem(Item item) { items.remove(item); } public boolean contains(Item item) { return items.contains(item); } }
public class ItemContainerTest extends TestCase { public void test() { Item item = new Item("aaa"); ItemContainer container = new ItemContainer(); container.addItem(item); assertTrue(container.contains(item)); } }after:
public class Item { private String name; public Item(String name) { this.name = name; } }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public void removeItem(Item item) { items.remove(item); } public boolean contains(Item item) { return items.contains(item); } public int size() { return items.size(); } }
public class ItemContainerTest extends TestCase { public void testContains() { Item item = new Item("aaa"); ItemContainer container = new ItemContainer(); container.addItem(item); assertTrue(container.contains(item)); } public void testSize() { ItemContainer container = new ItemContainer(); container.addItem( new Item("aaa") ); container.addItem( new Item("bbb") ); assertEquals(2, container.size()); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
既存の interface の実装
タイプ:
before:
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public class ItemContainer { private Listafter:- items = new ArrayList
- (); public void add(Item item) { items.add(item); } public void remove(Item item) { items.remove(item); } }
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public class ItemContainer implements Iterable<Item> { private List<Item> items = new ArrayList<Item>(); public void add(Item item) { items.add(item); } public void remove(Item item) { items.remove(item); } public Iterator<Item> iterator() { return items.iterator(); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
boolean query method 関連
boolean query method の追加
タイプ:
before:
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public class ItemContainer { private List items = new ArrayList(); public void add(Item item) { items.add(item); } public void remove(Item item) { items.remove(item); } }after:
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public class ItemContainer { private List items = new ArrayList(); public void add(Item item) { items.add(item); } public void remove(Item item) { items.remove(item); } public boolean isEmpty() { return items.isEmpty(); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
composite boolean query method の追加
タイプ:
進化タイプ:
前提:
構成要素:
public class Component { private String s; public Component(String s) { this.s = s; } public boolean isAAA() { return s.equals("AAA"); } public boolean isBBB() { return s.equals("BBB"); } }after:
public class Component { private String s; public Component(String s) { this.s = s; } public boolean isAAA() { return s.equals("AAA"); } public boolean isBBB() { return s.equals("BBB"); } public boolean isAAAorBBB() { return isAAA() || isBBB(); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
public boolean query method の追加
タイプ:
進化タイプ:
前提:
構成要素:
public class Player { private int hp; private int maxHP; public Player(int hp, int maxHP) { this.hp = hp; this.maxHP = maxHP; } public void setHP(int hp) { this.hp = hp; } public int getHP() { return hp; } public String getState() { if (hp <= 0) { return "Dead"; } else { return "Normal"; } } }
ppublic class PlayerClient { public void printStatus(Player player) { System.out.println( player.getState() ); System.out.println( player.getHP() ); } }after:
public class Player { private int hp; private int maxHP; public Player(int hp, int maxHP) { this.hp = hp; this.maxHP = maxHP; } public void setHP(int hp) { this.hp = hp; } public int getHP() { return hp; } public String getState() { if (hp <= 0) { return "Dead"; } else { return "Normal"; } } public boolean isMaxHP() { return hp == maxHP; } }
public class PlayerClient { public void printStatus(Player player) { System.out.println( player.getState() ); System.out.println( player.getHP() ); System.out.println( player.isMaxHP() ); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
private boolean query method の追加
タイプ:
進化タイプ:
前提:
構成要素:
public class Player { private int hp; public Player(int hp) { this.hp = hp; } public String getState() { if (hp <= 0) { return "Dead"; } else { return "Normal"; } } }after:
public class Player { private int hp; public Player(int hp) { this.hp = hp; } public String getState() { if ( isDead() ) { return "Dead"; } else { return "Normal"; } } private boolean isDead() { return hp <= 0; } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
ファクトリメソッド関連
public メソッドからの private なファクトリメソッドの抽出
タイプ:リファクタリング。
進化タイプ:モジュール内進化。
前提:public なメソッドが存在する。
構成要素:
public class Product { private String param; public Product(String param) { this.param = param; } }
public class Component { public void publicMethod() { // ... 処理 String type = // ... オブジェクト生成用のパラメータ Product product; if (type.equals("type_a")) { product = new Product("param_a"); } else if (type.equals("type_b")) { product = new Product("param_b"); } else { product = new Product("no_param"); } // ... product を使った処理 } }after:
public class Product { // 変更なし private String param; public Product(String param) { this.param = param; } }
public class Component { public void publicMethod() { // ... 処理 String type = // ... オブジェクト生成用のパラメータ Product product = createProduct(type); // ... product を使った処理 } private Product createProduct(String type) { // factory method if (type.equals("type_a")) { return new Product("param_a"); } else if (type.equals("type_b")) { return new Product("param_b"); } else { return new Product("no_param"); } } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public な具象ファクトリメソッドへのパラメータの追加
タイプ:
進化タイプ:
前提:public な具象ファクトリメソッドが存在する。
構成要素:
public class StringListFactory { public Listafter:create(String param1) { // パラメータを使ってオブジェクトを生成 List list = new ArrayList (); // ... return list; } }
public class StringListFactory { public Listcreate(String param1, String param2) { // パラメータを使ってオブジェクトを生成 List list = new ArrayList (); // ... return list; } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public な具象ファクトリメソッドのパラメータの削除
タイプ:
進化タイプ:
前提:パラメータを持つ public な具象ファクトリメソッドが存在する。
構成要素:
public class StringListFactory { public Listafter:create(String param1, int param2) { // 適当にオブジェクトを生成 List list = new ArrayList (); // パラメータを使って要素を追加 // ... return list; } }
public class StringListFactory { public Listcreate(String param) { // 不要なパラメータを削除 List list = new ArrayList (); // パラメータを使って要素を追加 // ... return list; } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public メソッドからの private メソッドの抽出
タイプ:
進化タイプ:モジュール内進化
前提:
構成要素:
public class Component { public void method() { // 何らかの処理 System.out.println("***"); System.out.println("aaa"); System.out.println("***"); } }after:
public class Component { public void method() { // 何らかの処理 System.out.println("***"); privateMethod(); System.out.println("***"); } private void privateMethod() { System.out.println("aaa"); } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
ユーティリティクラスへの static メソッドの追加
タイプ:
before:
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public class ItemUtils { public static String[] getNames(Item[] items) { String[] names = new String[items.length]; for(int i = 0 ; i < items.length; i++) { names[i] = items[i].getName(); } return names; } }after:
public class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } }
public interface ItemFilter { public boolean accept(Item item); }
public class ItemUtils { public static String[] getNames(Item[] items) { String[] names = new String[items.length]; for(int i = 0 ; i < items.length; i++) { names[i] = items[i].getName(); } return names; } public static Item[] filterItems(Item[] items, ItemFilter filter) { List itemList = new ArrayList(); for(int i = 0; i < items.length; i++) { if ( filter.accept(items[i]) ) { itemList.add(items[i]); } } return (Item[])itemList.toArray(new Item[itemList.size()]); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
実装クラスの追加
タイプ:
構成要素:
before:
public interface MyInterface { public void method(); }
public class MyInterfaceImplA implements MyInterface { public void method() { System.out.println("MyInterfaceImplA.method()"); } }after:
public interface MyInterface { public void method(); }
public class MyInterfaceImplA implements MyInterface { public void method() { System.out.println("MyInterfaceImplA.method()"); } }
public class MyInterfaceImplB implements MyInterface { public void method() { System.out.println("MyInterfaceImplB.method()"); } }
参考文献とリソース
パターン関係
進化パス
関連パターン
参考文献とリソース
todo
Filter interface の導入
タイプ:
before:
public class Item { private String name; private int price; public Item(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public Item[] getItems() { return (Item[])items.toArray(new Item[items.size()]); } }after:
public class Item { // 変更なし private String name; private int price; public Item(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
public interface ItemFilter { public boolean accpet(Item item); }
public class ItemContainer { private List items = new ArrayList(); public void addItem(Item item) { items.add(item); } public Item[] getItems() { return (Item[])items.toArray(new Item[items.size()]); } public Item[] getItems(ItemFilter filter) { List itemList = new ArrayList(); Item[] allItems = getItems(); for(int i = 0; i < allItems.length; i++) { if ( filter.accpet(allItems[i]) ) { itemList.add(allItems[i]); } } return (Item[])itemList.toArray(new Item[itemList.size()]); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アノテーションの追加
タイプ:
before:
after:
public @interface MyAnnotation { }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
メソッドの抽出によるユーティリティクラスの追加
タイプ:
before:
public class MyClass { public void method1() { method2("abc"); } private void method2(String str) { System.out.println(str); } }after:
public class MyClass { public void method1() { MyUtils.method("abc"); } }
public class MyUtils { public static void method(String str) { System.out.println(str); } }
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
varargs method の追加
タイプ:
進化タイプ:
前提:
構成要素:
public class StringContainer { private Listsrts = new ArrayList (); public void addString(String s) { srts.add(s); } }
public class StringContainerClient { public void method() { StringContainer c = new StringContainer(); c.addString("aaa"); c.addString("bbb"); c.addString("ccc"); } }after:
public class StringContainer { private Listsrts = new ArrayList (); public void addString(String s) { srts.add(s); } public void addStrings(String... ss) { srts.addAll( Arrays.asList(ss) ); } }
public class StringContainerClient { public void method() { StringContainer c = new StringContainer(); c.addStrings("aaa", "bbb", "ccc"); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
その他/疑問
メソッドのパラメータの削除
タイプ:
進化タイプ:
前提:パラメータを持つメソッドが存在する。
構成要素:
public class Component { public void method(String param) { System.out.println(param); System.out.println("***"); // 何かの処理 } }after:
public class Component { public void method() { System.out.println("***"); // 何かの処理 } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public メソッドのパラメータの削除
タイプ:
進化タイプ:
前提:パラメータを持つ public メソッドが存在する。
構成要素:
public class Component { public void method(String param) { System.out.println(param); System.out.println("***"); // 何かの処理 } }after:
public class Component { public void method() { System.out.println("***"); // 何かの処理 } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
public な具象メソッドのパラメータの削除
タイプ:
進化タイプ:
前提:パラメータを持つ public な具象メソッドが存在する。
構成要素:
public class Component { public void method(String param) { System.out.println(param); System.out.println("***"); // 何かの処理 } }after:
public class Component { public void method() { System.out.println("***"); // 何かの処理 } }
進化リクエスタ/プロバイダ
議論
例
パターン関係
進化パス
関連パターン
参考文献とリソース
その他/疑問
View コードの変更
タイプ:
進化タイプ:
前提:
before:
public class Model { private String data; public Model(String data) { this.data = data; } public String getData() { return data; } }
import java.awt.Graphics; public class View { private Model model; public View(Model model) { this.model = model; } public void draw(Graphics g) { g.drawString(model.getData(), 50, 50); } }
import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JPanel; public class MyPanel extends JPanel { private Model model; private View view; public MyPanel() { setPreferredSize(new Dimension(100, 100)); model = new Model("aaa"); view = new View(model); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); view.draw(g); } }
import javax.swing.JFrame; public class Main { public static void main(String[] args) { JFrame f = new JFrame(); f.add(new MyPanel()); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); } }after:
public class Model { private String data; public Model(String data) { this.data = data; } public String getData() { return data; } }
import java.awt.Graphics; public class View { private Model model; public View(Model model) { this.model = model; } public void draw(Graphics g) { g.drawString("data: " + model.getData(), 50, 50); } }
import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JPanel; public class MyPanel extends JPanel { private Model model; private View view; public MyPanel() { setPreferredSize(new Dimension(100, 100)); model = new Model("aaa"); view = new View(model); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); view.draw(g); } }
import javax.swing.JFrame; public class Main { public static void main(String[] args) { JFrame f = new JFrame(); f.add(new MyPanel()); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); } }
進化リクエスタ/プロバイダ
議論
例
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
ハードコードされたパラメータ設定を DI コンテナにより外部設定化
public class Config { private String param1; private int param2; public void setParam1(String param1) { this.param1 = param1; } public String getParam1() { return param1; } public void setParam2(int param2) { this.param2 = param2; } public int getParam2() { return param2; } }
public class Main { public static void main(String[] args) { Config config = new Config(); config.setParam1("xyz"); config.setParam2(100); } }after:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="config" class="evo.di.Config"> <property name="param1"><value>xyz</value></property> <property name="param2"><value>100</value></property> </bean> </beans>
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { BeanFactory factory = new ClassPathXmlApplicationContext("bean.xml"); Config config = (Config)factory.getBean("config"); } }
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Setter の追加
public class Component { }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="comp" class="evo.spring.setter.Component"/> </beans>after:
public class Component { private String name; public void setName(String name) { this.name = name; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="comp" class="evo.spring.setter.Component"> <property name="name"><value>my</value></property> </bean> </beans>
参考文献とリソース
todo
Spring: value/ref のショートカット
public class MyBean { private String value1; private String value2; public void setValue1(String value1) { this.value1 = value1; } public String getValue1() { return value1; } public void setValue2(String value2) { this.value2 = value2; } public String getValue2() { return value2; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="mybean" class="evo.spring.shortcut.MyBean"> <property name="value1"> <value>aaa</value> </property> <property name="value2"> <value>bbb</value> </property> </bean> </beans>after:
public class MyBean { // 変更なし private String value1; private String value2; public void setValue1(String value1) { this.value1 = value1; } public String getValue1() { return value1; } public void setValue2(String value2) { this.value2 = value2; } public String getValue2() { return value2; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="mybean" class="evo.spring.shortcut.MyBean"> <property name="value1" value="aaa"/> <property name="value2" value="bbb"/> </bean> </beans>
参考文献とリソース
todo
ハードコードされた Preprocess Command の外部設定化
before:
public class Data { // データを編集する適当なメソッド }
public interface PreprocessCommand { public void execute(Data data); }
public class ConcretePreprocessCommandA implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandA - param = " + param); } }
public class ConcretePreprocessCommandB implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandB - param = " + param); } }
public class ConcretePreprocessCommandC implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandC - param = " + param); } }
public class PreprocessCommandExecutor { private List commands = new ArrayList(); public void addCommand(PreprocessCommand command) { commands.add(command); } public void execute(Data data) { for(Iterator itr = commands.iterator(); itr.hasNext(); ) { ( (PreprocessCommand)itr.next() ).execute(data); } } }
public class Main { public static void main(String[] args) { Data data = new Data(); ConcretePreprocessCommandA commA = new ConcretePreprocessCommandA(); commA.setParam("aaa"); ConcretePreprocessCommandB commB = new ConcretePreprocessCommandB(); commB.setParam("bbb"); ConcretePreprocessCommandC commC = new ConcretePreprocessCommandC(); commC.setParam("ccc"); PreprocessCommandExecutor executor = new PreprocessCommandExecutor(); executor.addCommand(commA); executor.addCommand(commB); executor.addCommand(commC); executor.execute(data); } }after:
public class Data { // データを編集する適当なメソッド }
public interface PreprocessCommand { public void execute(Data data); }
public class ConcretePreprocessCommandA implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandA - param = " + param); } }
public class ConcretePreprocessCommandB implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandB - param = " + param); } }
public class ConcretePreprocessCommandC implements PreprocessCommand { private String param; public void setParam(String param) { this.param = param; } public void execute(Data data) { // param を利用してデータの前処理 System.out.println("ConcretePreprocessCommandC - param = " + param); } }
public class PreprocessCommandExecutor { private List commands = new ArrayList(); public void addCommand(PreprocessCommand command) { commands.add(command); } public void setCommandList(List commandList) { for(Iterator itr = commandList.iterator(); itr.hasNext(); ) { addCommand( (PreprocessCommand)itr.next() ); } } public void execute(Data data) { for(Iterator itr = commands.iterator(); itr.hasNext(); ) { ( (PreprocessCommand)itr.next() ).execute(data); } } }
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main2 { public static void main(String[] args) { Data data = new Data(); BeanFactory factory = new ClassPathXmlApplicationContext("bean.xml"); PreprocessCommandExecutor executor = (PreprocessCommandExecutor)factory.getBean("commandExecutor"); executor.execute(data); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="commandExecutor" class="evo.command.PreprocessCommandExecutor"> <property name="commandList"> <list> <ref bean="commA"/> <ref bean="commB"/> <ref bean="commC"/> </list> </property> </bean> <bean id="commA" class="evo.command.ConcretePreprocessCommandA"> <property name="param" value="aaa"/> </bean> <bean id="commB" class="evo.command.ConcretePreprocessCommandB"> <property name="param" value="bbb"/> </bean> <bean id="commC" class="evo.command.ConcretePreprocessCommandC"> <property name="param" value="ccc"/> </bean> </beans>
進化パス
関連パターン
参考文献とリソース
todo
ハードコードされた Strategy の外部設定化
before:
public interface Strategy { public void execute(); }
public class ConcreteStrategyA implements Strategy { public void execute() { System.out.println("strategyA"); } }
public class ConcreteStrategyB implements Strategy { public void execute() { System.out.println("strategyB"); } }
public class ConcreteStrategyC implements Strategy { public void execute() { System.out.println("strategyC"); } }
public class Context { private List strategies = new ArrayList(); public void addStrategy(Strategy strategy) { strategies.add(strategy); } public void executeStrategies() { for(Iterator itr = strategies.iterator(); itr.hasNext();) { Strategy strategy = (Strategy)itr.next(); strategy.execute(); } } }
public class Main { public static void main(String[] args) { Context context = new Context(); context.addStrategy( new ConcreteStrategyA() ); context.addStrategy( new ConcreteStrategyB() ); context.addStrategy( new ConcreteStrategyC() ); context.executeStrategies(); } }after:
public interface Strategy { public void execute(); }
public class ConcreteStrategyA implements Strategy { public void execute() { System.out.println("strategyA"); } }
public class ConcreteStrategyB implements Strategy { public void execute() { System.out.println("strategyB"); } }
public class ConcreteStrategyC implements Strategy { public void execute() { System.out.println("strategyC"); } }
public class Context { private List strategies = new ArrayList(); public void addStrategy(Strategy strategy) { strategies.add(strategy); } public void setStrategies(List strategies) { for(Iterator itr = strategies.iterator(); itr.hasNext();) { addStrategy( (Strategy)itr.next() ); } } public void executeStrategies() { for(Iterator itr = strategies.iterator(); itr.hasNext();) { Strategy strategy = (Strategy)itr.next(); strategy.execute(); } } }
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { BeanFactory factory = new ClassPathXmlApplicationContext("bean.xml"); Context context = (Context)factory.getBean("context"); context.executeStrategies(); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="context" class="evo.strategy2.strategy.spring.Context"> <property name="strategies"> <list> <bean class="evo.strategy2.strategy.spring.ConcreteStrategyA"/> <bean class="evo.strategy2.strategy.spring.ConcreteStrategyB"/> <bean class="evo.strategy2.strategy.spring.ConcreteStrategyC"/> </list> </property> </bean> </beans>
進化パス
関連パターン
参考文献とリソース
todo
ハードコードされた Strategy の外部設定化2
タイプ:リファクタリング
before:
public interface Strategy { public void algorithmInterface(); }
public class ConcreteStrategy implements Strategy { private String paramA; private int paramB; public void algorithmInterface() { System.out.println("param A = " + paramA); System.out.println("param B = " + paramB); } public void setParameterA(String paramA) { this.paramA = paramA; } public void setParameterB(int paramB) { this.paramB = paramB; } }
public class Context { public void contextInterface(Strategy strategy) { strategy.algorithmInterface(); } }
public class Main { public static void main(String[] args) { ConcreteStrategy strategy = new ConcreteStrategy(); strategy.setParameterA("aaa"); strategy.setParameterB(100); Context context = new Context(); context.contextInterface(strategy); } }after:
public interface Strategy { // 変更なし public void algorithmInterface(); }
public class ConcreteStrategy implements Strategy { // 変更なし private String paramA; private int paramB; public void algorithmInterface() { System.out.println("param A = " + paramA); System.out.println("param B = " + paramB); } public void setParameterA(String paramA) { this.paramA = paramA; } public void setParameterB(int paramB) { this.paramB = paramB; } }
public class Context { // 変更なし public void contextInterface(Strategy strategy) { strategy.algorithmInterface(); } }
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) throws Exception { BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml"); ConcreteStrategy strategy = (ConcreteStrategy)factory.getBean("strategy"); Context context = new Context(); context.contextInterface(strategy); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="strategy" class="evo.spring.externalize.strategy.after.ConcreteStrategy"> <property name="parameterA" value="aaa"/> <property name="parameterB" value="100"/> </bean> </beans>
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Injected クラスの追加
タイプ:
before:
after:
public class InjectedClass { private String name; public void method() { System.out.println("name : " + name); } public void setName(String name) { this.name = name; } }
import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author asato */ public class Main { public static void main(String[] args) throws Exception { BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml"); InjectedClass injected = (InjectedClass)factory.getBean("injected"); injected.method(); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="injected" class="evo.add_injected_class.after.InjectedClass"> <property name="name" value="aaa"/> </bean> </beans>
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Injected Setter Method の追加
タイプ:リファクタリング
before:
public class MyLogger { public void log(String str) { System.out.println(str); } }after:
public class MyLogger { private boolean enabled; public void log(String str) { if (enabled) { System.out.println(str); } } public void setEnabled(boolean enabled) { this.enabled = enabled; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="logger" class="evo.spring.add_injected_setter_method.after.MyLogger"> <property name="enabled" value="true"/> </bean> </beans>
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
参考文献とリソース
更新履歴
todo