複合模式
定義: 結合兩個或以上的模式在一個解決方案。
又是鴨子範例
首先先建立一個Quackable介面
public interface Quackable {
public void quack(); //呱呱叫
}
有天某些鴨子實踐了Quackable
public class MallardDuck implements Quackable { //綠頭鴨
public void quack() {
System.out.println("Quack");
}
}
public class RedheadDuck implements Quackable { //紅頭鴨
public void quack() {
System.out.println("Quack");
}
}
public class DuckCall implements Quackable { //誘餌鴨
public void quack() {
System.out.println("Kawk");
}
}
public class RubberDuck implements Quackable { //橡膠鴨
public void quack() {
System.out.println("Squeak");
}
}
實作囉
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}
void simulate() {
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck ();
Quackable duckCall = new DuckCall();
Quackable rubberDuck = new RubberDuck();
System.out.println("Duck Simulator");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator
Quack
Quack
Kwak
Squeak
目前為止一切順利
但...此時鵝出現了!
public class Goose {
public void honk() {
System.out.println("Honk"); //鵝鵝叫
}
}
轉接器模式
(弓箭手也想丟火球?
public class GooseAdapter implements Quackable { //轉接器會實踐目的介面
Goose goose;
public GooseAdpter(Goose goose) {
this.goose = goose;
}
public void quack() {
goose.honk();
}
}
把轉接器模式加入(修改code part1)
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}
void simulate() {
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck ();
Quackable duckCall = new DuckCall();
Quackable rubberDuck = new RubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("Duck Simulator");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator
Quack
Quack
Kwak
Squeak
Honk
呱呱叫專家要知道叫的次數
裝飾者模式
(星巴茲咖啡 加摩卡加奶泡...
public class QuackCounter implements Quackable { //裝飾者實踐目的介面
Quackable duck;
static int numberOfQuacks;
public QuackCounter (Quackable duck) {
this.duck = duck;
}
public void quack() {
duck.quack();
numberOfQuacks++;
}
public static int getQuacks() {
return numberOfQuacks;
}
}
把裝飾者模式加入(修改code part2)
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulate();
}
void simulate() {
Quackable mallardDuck = new QuackCounter(new MallardDuck()); //用QuackCounter包裝
Quackable redheadDuck = new QuackCounter(new RedheadDuck());
Quackable duckCall = new QuackCounter(new DuckCall());
Quackable rubberDuck = new QuackCounter(new RubberDuck());
Quackable gooseDuck = new GooseAdapter(new Goose()); //因為是鵝不加入裝飾
System.out.println("Duck Simulator");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);
System.out.println("鴨子叫了" + QuackCounter.getQuacks() + "次");
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator
Quack
Quack
Kwak
Squeak
Honk
鴨子叫了 4 次
為了品質管制鴨子,確保鴨子一定被包裝進裝飾者中,我們要建立一個工廠產生鴨子
工廠模式
(辭職賣Pizza的故事,建立自己的原料工廠
public abstract class AbstractDuckFactory { //定義抽象工廠
public abstract Quackable creatMallarDuck(); //每個方法建立一種鴨子
public abstract Quackable creatRedheadDuck();
public abstract Quackable creatDuckCall();
public abstract Quackable creatRubberDuck();
}
鴨子工廠
public DuckFactory extends AbstractDuckFactory { //擴充抽象工廠
public abstract Quackable creatMallarDuck() { //每一個方法都建立一種鴨子
return new MallarDuck();
}
public abstract Quackable creatRedheadDuck() {
return new RedheadDuck();
}
public abstract Quackable creatDuckCall() {
return new DuckCall();
}
public abstract Quackable creatRubberDuck() {
return new RubberDuck();
}
}
加入裝飾者的鴨子工廠
public CountingDuckFactory extends AbstractDuckFactory { //擴充抽象工廠
public abstract Quackable creatMallarDuck() {
return new QuackCounter(new MallardDuck());
}
public abstract Quackable creatRedheadDuck() {
return new QuackCounter(new RedheadDuck());
}
public abstract Quackable creatDuckCall() {
return new QuackCounter(new DuckCall());
}
public abstract Quackable creatRubberDuck() {
return new QuackCounter(new RubberDuck());
}
}
把工廠模式加入(修改code part3)
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactort duckFactory = new CountingDuckFactory(); //建立一個工廠 傳進simulate
simulator.simulate(duckFactory);
}
void simulate( AbstractDuckFactort duckFactory ) {
Quackable mallardDuck = duckFactory.creatMallardDuck(); //建立鴨子
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("Duck Simulator : 加入工廠模式");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);
System.out.println("鴨子叫了" + QuackCounter.getQuacks() + "次");
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator : 加入工廠模式
Quack
Quack
Kwak
Squeak
Honk
鴨子叫了 4 次
//結果與上次一樣,但這次用了數鴨工,確保每隻鴨都有被裝飾到。
結果與上次一樣,但這次用了數鴨工,確保每隻鴨都有被裝飾到。
他們還想管理一群鴨子,
如果我們能夠下一次命令就能讓所有的鴨子聽命令行事
合成模式
(樹狀結構?
將一群物件視為一個物件
public class Flock implements Quackable { //建立一個群
ArrayList quackers = new ArrayList;
public void add(Quackable quacker) {
quackers.add(quacker);
}
public void quack() {
Iterator iterator = quackers.iterator(); //這裡是反覆器模式
while (iterator.hasNext()) {
Quackable quacker = (Quackable)iterator.next();
quacker.quack();
}
}
}
把合成模式加入(修改code part4)
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactort duckFactory = new CountingDuckFactory();
simulator.simulate(duckFactory);
}
void simulate( AbstractDuckFactort duckFactory ) {
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("Duck Simulator : 加入合成模式");
Flock flockOfDucks = new Flock(); //建立一個主群
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
flockOfDucks.add(gooseDuck);
Flock flockOfMallards = new Flock(); //再建立一個綠頭鴨群
Quackable mallardOne = duckFactory.creatMallardDuck();
Quackable mallardTwo = duckFactory.creatMallardDuck();
Quackable mallardThree = duckFactory.creatMallardDuck();
Quackable mallardFour = duckFactory.creatMallardDuck();
flockOfMallards.add(mallardOne); //加入綠頭鴨群
flockOfMallards.add(mallardTwo);
flockOfMallards.add(mallardThree);
flockOfMallards.add(mallardFour);
flockOfDucks.add(flockOfMallards); //把綠頭鴨加入組群
System.out.println("鴨主群:");
simulate(flockOfDucks);
System.out.println("綠頭鴨群:");
simulate(flockOfMallards);
System.out.println("鴨子叫了" + QuackCounter.getQuacks() + "次");
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator : 加入合成模式
鴨主群:
Quack
Kwak
Squeak
Honk
Quack
Quack
Quack
Quack
綠頭鴨群:
Quack
Quack
Quack
Quack
鴨子叫了 11 次
新需求:能夠追蹤每隻鴨子,當有鴨子叫時,馬上通知。
觀察者模式
(天氣站問題
建立一個 QuackObservable 介面 (呱呱叫的可觀察介面)
public interface QuackObservable {
public void registerObserver(Observer observer); //觀察者必須實踐Observer介面
public void notifyObserver(); //通知觀察者的方法
}
讓Quackable 擴充此介面
public interface Quackable extends QuackObservable {
public void quack();
}
建立一個輔助類別 Observable (可觀察類)
只要把它插進任何類別,就可讓該類別將工作給Observable進行。
public class Observable implements QuackObservable {
ArrayList observers = new ArrayList();
QuackObservable duck;
public Observable(QuackObservable duck) {
this.duck = duck;
}
public void registerObserver(Observer observer) { //註冊觀察者
observers.add(observer);
}
public void notifyObserver() { //通知
Iterator iterator = observers.iterator();
while (iterator.hasNext()) {
Observer observer = (Observer)iterator.next();
observer.update(duck);
}
}
}
修改鴨類別 (綠頭鴨)
public class MallardDuck implements Quackable {
Observable observable;
public void MallardDuck() { //建構式建立Observable
observable = new Observable(this);
}
public void quack() {
System.out.println("Quack");
notifyObserver(); //呱呱叫時要讓觀察者知道
}
public void registerObserver(Observer observer) { //把工作交給observable進行
observable.registerObserver(observer);
}
public void notifyObserver() { //把工作交給observable進行
observable.notifyObservers();
}
}
...其他鴨也是
建立Observer (觀察者) 介面
public interface Observer {
public void update(QuackObservable duck);
}
現在我們需要一個觀察者:呱呱叫專家
public class Quackologist implements Observer { //印出正在呱呱叫的物件
public void update(QuackObservable duck) {
System.out.println("呱呱叫專家:" + duck + "叫囉");
}
}
把觀察者模式加入(修改code part5)
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactort duckFactory = new CountingDuckFactory();
simulator.simulate(duckFactory);
}
void simulate( AbstractDuckFactort duckFactory ) {
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("Duck Simulator : 合成模式加入觀察者模式");
Flock flockOfDucks = new Flock(); //建立一個主群
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
flockOfDucks.add(gooseDuck);
Quackologist quackologist = new Quackologist(); //建立呱呱叫專家 註冊成為一群觀察者
flockOfDucks.registerObserver(quackologist);
simulate(flockOfDucks); //模擬整群鴨
System.out.println("鴨子叫了" + QuackCounter.getQuacks() + "次");
}
void simulate(Quackable duck) {
duck.quack();
}
}
Duck Simulator : 合成模式加入觀察者模式
Quack
呱呱叫專家: Redhead Duck 叫囉 //每一次呱呱叫,觀察者都會收到通知
Kwak
呱呱叫專家: Duck Call叫囉
Squeak
呱呱叫專家: Rubber Duck 叫囉
Honk
呱呱叫專家: 假裝鴨的鵝 叫囉
鴨子叫了 3 次
我們共做了哪些模式
一開始有一堆鴨子物件
- 鵝的亂入 => 轉接器模式
- 需要紀錄呱呱叫的次數 => 裝飾者模式
- 擔心有漏網之鴨忘了裝飾的鴨子 =>工廠模式
- 又是鴨 又是鵝 又是 quackable 管理上有困擾 => 合成模式
- 任何鴨叫時需要被通知 =>觀察者模式
Model = 處理資料
View = 畫面顯示
Controller = M與C溝通橋梁