はたして、試験の中身はSunのときと同じなのかなぁ(´・ω・`)
よく調べると、試験コードがSunとOracleで同じ(例えば、JavaプログラマならCX-310-065)だから中身も同じだ!と期待。
ちなみに、Oracle認定のMySQL資格もあるw
よく調べると、試験コードがSunとOracleで同じ(例えば、JavaプログラマならCX-310-065)だから中身も同じだ!と期待。
ちなみに、Oracle認定のMySQL資格もあるw
public abstract class Subject {
private List<Observer> observerList = new ArrayList<Obsever>();
public void addObserver(Observer observer) {
observerList.add(observer);
}
protected void notifyObservers() {
// 参考本ではこのメソッドはpublicになっていたが、子クラスからしか呼ばれないので、protectedにした。
Iterator itr = observerList.iterator();
while (itr.hasNext()) {
Observer observer = (Observer) itr.next();
observer.update(this);
}
}
public abstract void execute();
// その他、observerから呼んで欲しいメソッドを定義
}
public interface Observer {
void update(Subject subject);
}
public class SampleObserver implements Observer {
public void update(Subject subject) {
// Subjectクラスのメソッドを呼び、例えばコンソールに出力する、ログに残すなどの処理を行う。
}
}
public class Facade {
・・・
public static void doSample() {
// 必要な処理を実装
}
・・・
}
public class Main {
public static void main(String[] args) {
Facade.doSample();
}
}
public abstract class Support {
・・・
private Support next;
・・・
public Support(String name) {
・・・
}
publilc Support setNext(Support next) {
this.next = next;
return next;
}
public final void support(Trouble trouble) {
if (resolve(trouble)) {
// 解決できた時の処理を記述
} else if (next != null) {
// 次の人にお願いする。
next.support(trouble);
} else {
// 次の人がいない(誰ひとりとして対処できなかった)時の処理を記述
}
}
protected abstract boolean resolve(Trouble trouble);
}
自分で対処できない場合に次の人にお願いするので、Supportクラスのインスタンスをnextフィールドで持つようにします。・・・ Support support1 = new Support1(・・・); Support support2 = new Support2(・・・); Support support3 = new Support3(・・・); support1.setNext(support2).setNext(support3);// 本当はJavaでメソッドチェーンを書くのはあまりおすすめしない・・・ ・・・ support1.support(new Trouble(・・・));このパターンの良いところは、クライアントはトラブル対処処理を知る必要がなく、1人目にお願いするだけで良いというところです。クライアントとサポートのつながりがゆるいということです。もし、クライアントがトラブル対処処理を知るとなると、密なつながりを持つことになってしまいます。
public void visit(File file) {
・・・
}
public void visit(Directori dir) {
・・・
}
ちなみに、訪問時の処理が複数考えられるならば、処理ごとにクラスを切り出します。上記のコードをabstractなVistorクラスとして書いておいて、そのクラスを継承したクラスを作ればいいです。public void accept(Visitor v) {
v.accept(this);
}
内部では、訪ねてきた人に処理をお願いします。渡すのは自身です。ということで、(Compositeパターンの例で言うと)Fileだったり、Directoryだったりします。本には書かれていないのですが、もし何かしらの理由で受け入れできない場合はここで例外を出すのが良いと思います。・・・
File file = new File("sample", 100);
file.accept(new SampleVisitor());
・・・
public abstract class SampleBase {
public abstract String getValue();
public final void print() {
System.out.println(getValue());
}
}
print()が呼ばれると子クラスで持っている文字列を表示します。もちろん飾りはついていれば飾りも合わせて表示されます。public class Sample extends SampleBase {
private String value;
public Sample(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
コンストラクタを介して文字列が渡されます。SampleBaseを継承しているので、getValue()を実装しています。ただ単にこのクラスが管理している文字列を返すだけです。public abstract class Decor extends SampleBase {
protected SampleBase sampleBase;
public Decor(SampleBase sampleBase) {
this.sampleBase = sampleBase;
}
}
飾り付けも表示されるのでSampleBaseを継承しているのが特徴です。そして、自身は何に対して飾り付けるのかを知っておく必要がありますので、sampleBaseを持っています。public class SharpDecor extends Decor {
public SharpDecor(SampleBase sampleBase) {
super(sampleBase);
}
public String getValue() {
return "#" + sampleBase.getValue() + "#";
}
}
コンストラクタを介して、飾り付けの対象を受け取ります。Sampleが渡されることがあるのは分かると思いますが、Decorを継承したオブジェクトが渡されることもあります。そして、そのDecor継承クラスは飾り付けの対象を知っていて・・・という風に構造が再帰的になります。これがDecoratorパターンの特徴です。ちなみに、SampleBaseもDecorもabstractなので、getValueメソッドはここで実装します。ここでは、飾り付けの対象からgetvalueメソッドで値を取り出し、#で「飾り付け」をして返しています。public class BracketDecor extends Decor {
public BracketDecor(SampleBase sampleBase) {
super(sampleBase);
}
public String getValue() {
return "<" + sampleBase.getValue() + ">";
}
}
Mainは以下のとおりです。public class Main {
public static void main(String[] args) {
SampleBase sample = new Sample("sample");
sample.print(); // 何も飾りつけずに表示
SampleBase sample2 = new SharpDecor(sample);
sample2.print(); // #で飾り付け
SampleBase sample3 = new BracketDecor(sample);
sample3.print(); // <>で飾り付け
SampleBase sample4 = new BracketDecor(sample2);
sample4.print(); // #で飾りつけたサンプルに<>で飾り付け
}
}
一番最初にSampleインスタンスを作り、まずは何も飾り付けずに表示します。その後に#で飾り付けた場合、<>で飾り付けた場合を表示し、最後に#で飾り付けたsample2を更に<>で飾り付けるという流れになっています。public interface Strategy {
public void exec();
}
public interface AStrategy {
・・・
public AStrategy(・・・) {
・・・
}
public void exec() {
// AStrategy特有のアルゴリズムを実装
}
}
public interface BStrategy {
・・・
public BStrategy(・・・) {
・・・
}
public void exec() {
// BStrategy特有のアルゴリズムを実装
}
}
mainクラスでは以下のように呼びます。public static void main(String[] args) {
Strategy aStrategy = new AStrategy(・・・);
Strategy bStrategy = new BStrategy(・・・);
・・・
aStrategy.exec();
bStrategy.exec();
・・・
}
あくまでこれは例なので、ある条件の時はaStrategy、そうでないときはbStrategyにしてももちろん構いません。あるいはaStrategy実行中に何かしらの理由でbStrategyに切り替えることもあるかと思います。ここがミソで、このパターンを利用するとアルゴリズムを容易に切り替えられるということなのです。public class DisplaySample {
private DisplayImpl impl;
public DisplaySample(DisplayImpl impl) {
this.impl = impl;
}
public void print() {
impl.print();
}
}
public class ExtendedDisplaySample extends DisplaySample {
public ExtendedDisplaySample(DisplayImpl impl) {
super(impl);
}
public void printTwice() {
System.out.print("1回め:");
print();
System.out.print("2回め:");
print();
}
}
public interface DisplayImpl {
public void print();
}
public class AsteriskDisplayImpl implements DisplayImpl {
private String value;
public AsteriskDisplayImpl(String value) {
this.value = value;
}
public void print() {
System.out.println("*** " + value + " ***");
}
}
public class UpperLowerDisplayImpl implements DisplayImpl {
private String value;
public UpperLowerDisplayImpl(String value) {
this.value = value;
}
public void print() {
// valueをchar配列に変換
char[] valueChars = value.toCharArray();
// 大文字小文字を変換した後の文字を格納するビルダー
StringBuilder sb = new StringBuilder();
// 1文字ずつ、大文字か小文字かを判別し、ビルダーに変換後の文字を
// 格納していく
for (char ch : valueChars) {
if (Character.isLowerCase(ch)) {
sb.append(Character.toUpperCase(ch));
} else {
sb.append(Character.toLowerCase(ch));
}
}
// toString()を呼び出して文字列として表示
System.out.println(sb.toString());
}
}
よくよく考えると、わざわざchar配列を用意しなくても、ループ中にvalue.charAt()を使えばいいよねorzpublic class Main {
public static void main(String[] args) {
DisplaySample dis1 = new DisplaySample(new AsteriskDisplayImpl("asterisk"));
DisplaySample dis2 = new DisplaySample(new UpperLowerDisplayImpl("upperLOWER"));
ExtendedDisplaySample ext1 = new ExtendedDisplaySample(new AsteriskDisplayImpl("twice / asterisk"));
ExtendedDisplaySample ext2 = new ExtendedDisplaySample(new UpperLowerDisplayImpl("twice / uPpErLoWeR"));
dis1.print();
dis2.print();
ext1.printTwice();
ext2.printTwice();
}
}
Mainでは、全部で4パターン用意してます。DisplaySampleとAsterisk、DisplaySampleとUpperLower、ExtendedとAsaterisk、ExtendedとupperLowerです。実行結果は以下のとおりです。public abstract class Part {
protected String name;
public Part(String name) {
this.name = name;
}
public abstract void doSomething();
}
public abstract class Factory {
public abstract Part createPart(String name);
}
import factory.Part;
public class ABCPart extends Part {
public ABCPart(String name) {
super(name);
}
public void doSomething() {
System.out.println("ABCPart - name: " + name);
}
}
ABCPartを扱うABCFactoryは以下の通りです。import factory.Factory;
import factory.Part;
public class ABCFactory extends Factory {
public Part createPart (String name) {
return new ABCPart(name);
}
}
2つ目はDEFPartです。ソースは以下の通りです。こちらのdoSomething()もnameを表示するだけですが、表示形式を変えています。import factory.Part;
public class DEFPart extends Part {
public DEFPart(String name) {
super(name);
}
public void doSomething() {
System.out.println("DEFPartです。名前は " + name + " です。");
}
}
DEFPartを扱うDEFFactoryは以下の通りです。import factory.Factory;
import factory.Part;
public class DEFFactory extends Factory {
public Part createPart (String name) {
return new DEFPart(name);
}
}
Factoryを扱うMainは以下の通りです。import factory.Factory;
import factory.Part;
import abc_factory.ABCFactory;
import def_factory.DEFFactory;
public class Main {
private static final String ABC_FACTORY = "ABCFactory";
private static final String DEF_FACTORY = "DEFFactory";
public static void main(String[] args) {
// TODO argsの長さが0だったり、2以上の場合があるので、その時はSystem.exit(0)を呼んで終了させる。
Factory factory = createFactory(args[0]);
Part part = factory.createPart("sample");
part.doSomething();
}
private static Factory createFactory(String factoryName) {
if (ABC_FACTORY.equals(factoryName)) {
return new ABCFactory();
} else if (DEF_FACTORY.equals(factoryName)) {
return new DEFFactory();
} else {
return null;// TODO こうすると呼び出し側でnullチェックをしないといけないので望ましくない。
}
}
}
ABCFactoryとDEFFactoryの2種類があるので、引数で選択します。ですが、実際にFactoryやPartに処理をお願いするときにはどちらのFactory、Partを使っているのか気にする必要はありません。前回やったパターンと同じで、共通のAPIを利用するだけです。public static Factory createFactory(String factoryName) {
Factory factory = null;
try {
factory = (Factory)Class.forName(factoryName).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return factory;
}
}
これはクラス名を引数にとり、ClassクラスのforName()で、指定したクラスを動的に読み込みます。読み込んだクラスのインスタンス化はnewInstance()です。こうすることで、import abc_factory.ABCFactoryと書いたり、new ABCFactory();と書く必要がなくなります。言い換えると、MainはABCFactory()などを知っておく必要はないということです。public abstract class Builder {
public abstract void makeEntrance();
public abstract void makeRoom(String name);
・・・
}
public class ABCBuilder extends Builder {
public void makeEntrance() {
・・・
}
public void makeRoom(String name) {
・・・
}
}
public class Director {
private Builder builder;
public Director (Builder builder) {
this.builder = builder;
}
public void construct() {
builder.makeEntrance();
builder.makeRoom("staff room");
・・・
}
}
コンストラクタの引数がBuilderクラスのオブジェクトになっています。ここに、特化した建築者を入れてあげます。ソースを見てのとおり、監督者はBuilderクラスのメソッドしか呼ばないため、具体的にどんな建築者がやってきたのかを監督者であるDirectorは知りません。ですが、監督者は別にそんなことを意識しなくても必要な操作、つまり、Builderクラスで定義したメソッドを呼ぶことができちゃいます。public static void main(String[] args) {
・・・
Director director = null;
if ("ABC".equals(args[0])) {
ABCBuilder abc = new ABCBuilder();
director = new Director(abc);
} else {
DEFBuilder def = new DEFBuilder();
director = new Director(def);
}
director.construct();
・・・
}
package framework;
import java.lang.Cloneable;
public interface Part extends Cloneable {
void doSomething();
Part copy();
}
package framework;
import java.util.Map;
import java.util.HashMap;
public class Manager {
private Map<String, Part> showcase = new HashMap<String, Part>();
public void register(String name, Part part) {
showcase.put(name, part);
}
public Part copyPart(String name) {
Part p = (Part)showcase.get(name);
return p.copy();
}
}
import framework.Part;
import framework.Manager;
public class Main {
public static void main(String[] args) {
// 準備
Manager manager = new Manager();
SamplePart part1 = new SamplePart("part1");
SamplePart2 part2 = new SamplePart2("part2");
manager.register("abc", part1);
manager.register("def", part2);
// 生成
Part p1 = manager.copyPart("abc");
p1.doSomething();
Part p2 = manager.copyPart("def");
p2.doSomething();
}
}
public class SingletonSample {
private static SingletonSample instance = new SingletonSample();
/**
* デフォルトコンストラクタ
* 外部から使用されないようにprivateにしている
*/
private SingletonSample() {}
public static SingletonSample getInstance() {
return instance;
}
}
このクラスのように、Singletonを実現する場合はSingletonSample obj1 = SingletonSample.getInstance();
SingletonSample obj1 = SingletonSample.getInstance();
SingletonSample obj2 = SingletonSample.getInstance();
if (obj1 == obj2) {
System.out.println("same");
} else {
System.out.println("different");
}
private static SingletonSample instance;
/**
* デフォルトコンストラクタ
* 外部から使用されないようにprivateにしている
*/
private SingletonSample() {}
public static SingletonSample getInstance() {
if (instance == null) {
instance = new SingletonSample();
}
return instance;
}
public abstract class Factory {
/**
* 商品を作る.
* @param name 商品名
*/
public final Product create(String name) {
Product p = createProduct(name);
doSomething(p);
return p;
}
protected abstract Product createProduct(String name);
protected abstract void doSomething(Product p);
}
public class SampleFactory extends Factory {
protected Product createProduct(name){
return new SampleProduct(name);
}
protected void doSomething(Product p) {
・・・
}
}
Factory factory = new SampleFactory();
Product product = factory.create("sample");
public abstract class AbstractSample {
protected abstract void start();
protected abstract void finish();
public final void execute() {
start();
System.out.println("execute");
finish();
}
}
public class Sample extends AbstractSample {
protected void start() {
System.out.println("--- Start ---");
}
protected void finish() {
System.out.println("--- Stop ---");
}
}
public class AnotherSample extends AbstractSample {
protected void start() {
System.out.println("*** スタート ***");
}
protected void finish() {
System.out.println("*** 終了 ***");
}
}
public class Main {
public static void main(String[] args) {
AbstractSample sample = new Sample();
sample.execute();
AbstractSample anotherSample = new AnotherSample();
anotherSample.execute();
}
}
public class Adapter extends Adaptee implements Target {
・・・
@override
public String getValue() {
// Adapteeクラスで用意されているメソッドを呼び、
// "value: "というprefixをつけて返す。
return "value: " + getSampleValue();
}
・・・
}
public class Adapter extends Target {
private Adaptee adaptee;
・・・
public String getValue() {
// Adapteeクラスで用意されているメソッドを呼び、
// "value: "というprefixをつけて返す。
return "value: " + adaptee.getSampleValue();
}
・・・
}
// SampleAggregateクラスはSampleクラスのオブジェクトを要素として、それを複数個持つクラス
Sample[] samples = sampleAggregate.getArray(); // 集合クラスが持つ配列を取得
for (int i = 0; i < samples.length; i++) {
・・・
}
となるがこの場合だと、Iterator itr = sampleAggregate.iterator();
while (itr.hasNext()) {
sample = (Sample) itr.next();
・・・
}
となり、上記2つのでメリットが克服できる。(もちろん、要素の管理方法が配列からArrayListに変わった場合はIteratorクラスは修正する必要があるが、集合クラスを利用する側は修正の必要がない)