Head First设计模式(阅读笔记)-14.复合模式

鸭子模拟器

学习了多种设计模式后,现在将这些设计模式用于重建鸭子模拟器


未加入设计模式
// 如果某个物体会发出叫声,就实现该接口
public interface Quackable{
   public void quack();
}
// 鸭鸣器(模仿鸭子叫声)
public class DuckCall implements Quackable{
   public void quack(){
       System.out.println("Kwak");
   }
}
// 测试鸭子模拟器
public class DuckSimulator{
   public static void main(String[] args){
       DuckSimulator simulator = new DuckSimulator();
       simulator.simulate();
   }
   public void simulate(){
       Quackable duckCall = new DuckCall();
       simulate(duckCall);
   }
   public void simulate(Quackable duck){
		duck.quack();
   }
}

加入适配器模式

因为鸭子和鹅生活在一起,此时想要在模拟器中也能使用到鹅,可以使用适配器将鹅适配成鸭子:

public class Goose{
    public void honk(){
        System.out.println("Honk");  // 鹅的叫声和鸭子不同
    }
}
public class GooseAdapter implements Quackable{  // 适配器实现目标接口
    Goose goose;
    public GooseAdapter(Goose goose){  // 传入需要适配的对象
        this.goose = goose;
    }
    public void quack(){
        goose.honk();
    }
}
// 测试鸭子模拟器
public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulate();
    }
    public void simulate(){
        Quackable gooseDuck = new GooseAdapter(new Goose());
        simulate(gooseDuck);
    }
    public void simulate(Quackable duck){
		duck.quack();
    }
}

加入装饰者模式

此时想要在不修改鸭子类的前提下给鸭子加上统计叫声次数的行为,可以使用装饰者模式:

// QuackCounter是装饰者
public class QuackCounter implements Quackable{  // 一样要实现目标接口
    Quackable duck;
    // 因为这里想要收集所有实现了Quackable接口对象的叫声数,所以定义为静态变量
    static int numOfQuck;
    public QuackCounter(Quackable duck){  // 传入需要装饰的对象
        this.duck = duck;
    }
    public void quack(){
        duck.quack();
        numOfQuck++;
    }
    public static int getQuacks(){
        return numOfQuck;
    }
}
// 测试鸭子模拟器
public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulate();
    }
    public void simulate(){
        Quackable duckCall = new QuackCounter(new DuckCall());
        simulate(duckCall);
        System.out.println(QuackCounter.getQuacks());  // 打印所有叫声数
    }
    public void simulate(Quackable duck){
		duck.quack();
    }
}

加入工厂模式

为了保证每个鸭子都是被装饰过的,为什么不使用流水线工作?这不就可以使用工厂模式(为了生产各种不同类型的鸭子,使用抽象工厂模式):

public abstract class AbstractDuckFactory{
    public abstract class Quakable createDuckCall();
    public abstract class Quakable createMallardDuck();
}
// 该工程生产装饰过的鸭子
public class CountingDuckDuckFactoy extends AbstractDuckFactory{
    public Quakable createDuckCall(){
        return new QuackCounter(new DuckCall());
    }
    public Quakable createMallardDuck(){
        return new QuackCounter(new MallardDuck());
    }
}
// 测试鸭子模拟器
public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        // 1.创建一个工厂
        AbstractDuckFactory duckFactory = new CountingDuckDuckFactoy();
        // 2.将工厂传入模拟器(模拟器只需要知道这个工厂是生产什么的,不需要知道它怎么生产)
        simulator.simulate(duckFactory);
    }
    public void simulate(AbstractDuckFactory duckFactory){
        // 使用工厂去创建
        Quackable duckCall = duckFactory.createDuckCall();
        Quackable mallardDuck = duckFactory.createMallardDuck();
        simulate(duckCall);
        simulate(mallardDuck);
        System.out.println(QuackCounter.getQuacks());  // 打印所有叫声数
    }
    public void simulate(Quackable duck){
		duck.quack();
    }
}

加入组合模式和迭代器模式

鸭子创建很多后就不好管理,如何实现下令就能让所有鸭子都发出叫声?可以使用组合模式将所有鸭子视为集合,并且使用迭代器模式遍历所有鸭子让其发出叫声:

// 组合需要和叶子节点实现相同的接口
public class Flock implements Quackable{
    ArrayList quackers = new ArrayList();
    public void add(Quackable quacker){
        quackers.add(quacker);
    }
    public void quack(){
        // 使用ArrayList中返回的迭代器
        Iterator iterator = quackers.iterator();
        while(iterator.hasNext()){
            Quackable quacker = (Quackable)iterator.next();
            quacker.quack();
        }
    }
}
// 测试鸭子模拟器
public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckDuckFactoy();
        simulator.simulate(duckFactory);
    }
    public void simulate(AbstractDuckFactory duckFactory){
        Quackable duckCall = duckFactory.createDuckCall();

        // Flock是一棵树,可以管理单个鸭子,也可以管理一个鸭群
        Flock flockOfDucks = new Flock();
        
        // 1.加入单个鸭子(叶子节点)
        flockOfDucks.add(duckCall);
        // 2.加入一个绿头鸭群
        Flock flockOfMallard = new Flock();  // 先创建一个绿头鸭子的子树
        Quackable mallardDuck1 = duckFactory.createMallardDuck();
        Quackable mallardDuck2 = duckFactory.createMallardDuck();
        flockOfMallard.add(mallardDuck1);
        flockOfMallard.add(mallardDuck2);
        flockOfDucks.add(flockOfMallard);  // 将该子树加入到总树中
        
        simulate(flockOfDucks);
        simulate(flockOfMallard);
        System.out.println(QuackCounter.getQuacks());  // 打印所有叫声数
    }
    public void simulate(Quackable duck){
		duck.quack();
    }
}

加入观察者模式

如果想追踪个别鸭子,那就可以使用观察者模式:

// 任何想被观察的Quackable都要实现该接口
public interface QuackObservable{  
    // 任何实现了Observer接口的对象都可以监听叫声
    public void registerObserver(Observer observer);
    public void notifyObservers();  // 通知观察者
}
public interface Quackable extends QuackObservable{  // 接口可以继承的
    public void quack();
}
// 辅助类
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 notifyObservers(){
		Iterator iterator = observers.iterator();
        while(iterator.hasNext()){
            Observer observer = (observer)iterator.next();
            observer.update(duck);  // 一旦有观察者存在更新,就通知该被观察者
        }
    }
}
public class MallardDuck implements Quackable{
    Observable observable;
    public MallardDuck(){
        observable = new Observable(this);
    }
    public void quack(){
        System.out.println("Quack");
        notifyObservers();  // 发出叫声就让观察者知道
    }
    // 委托给辅助类就行
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    public void notifyObservers(){
		observable.notifyObservers();
    }
}
// 观察者需要实现该接口
public interface Observer{
    public void update(QuackObservable duck);
}
// 专门观察鸭子叫声的学者
public class Quackologist implements Observer{
    public void update(QuackObservable duck){
		// 打印出正在叫的鸭子	
    }
}
// 测试鸭子模拟器
public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckDuckFactoy();
        simulator.simulate(duckFactory);
    }
    public void simulate(AbstractDuckFactory duckFactory){
        // 其余代码和上一节中一致
        Quackologist quackologist = new Quackologist();
        // 因为Flock实现了Quackable接口,而Quackable接口继承了QuackObservable接口,所以可以调用registerObserver方法
        flockOfDucks.registerObserver(quackologist);
    }
    public void simulate(Quackable duck){
		duck.quack();
    }
}

复合模式

  • 结合两个或以上的模式,组合一个解决方案,用于解决一再发生的一般性问题

参考

Head First 设计模式-复合模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值