Head First 设计模式 —— 14. 复合 (Compound) 模式

复合模式

在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。 P500

思考题
public interface Quackable {
    public void quack();
}

public class MallardDuck implements Quackable {
    public void quack() {
        System.out.println("Quack");
    }
}

public class Goose {
    public void honk() {
        System.out.println("Honk");
    }
}

假设我们想要在所有使用鸭子的地方使用鹅,毕竟鹅会叫、会飞、会游,和鸭子差不多。什么模式可以让我们轻易地将鸭子和鹅掺杂在一起呢? P503

  • 适配器模式。题目需要轻易地将一种行为转换为另一种行为,且不要改变原有的类,所以需要使用适配器转换。
思考题

我们要如何在不变化鸭子类的情况下,计算所有鸭子呱呱叫的总次数呢?有没有什么模式可以帮上忙?P505

  • 装饰器模式。题目要求增加新的行为,且不改变原有类,所以可以使用装饰器。
  • 代理模式。代理模式会控制访问,而鹅经适配器后转换的行为不应该被统计,所以可以通过代理模式进行控制。
思考题

你能够为鹅写一个抽象工厂吗?创建”内鹅外鸭“的对象时,你怎么处理? P511

  • 新建一个工厂,专门创建被适配器转换成鸭子的鹅

    public abstract class AbstractGooseDuckFactory {
        public abstract Quackable createGooseDuck();
    }
    
    public class GooseDuckFactory extends AbstractGooseDuckFactory {
        public Quackable createGooseDuck() {
            return new GooseAdapter(new Goose());
        }
    }
    
思考题

我们需要将鸭子视为一个集合,甚至是子集合(subcollection),如果我们下一次命令,就能让整个集合的鸭子听命行事,那就太好了。什么模式可以帮我们? P512

  • 迭代器模式。由于我们需要将鸭子视为一个集合,可以遍历执行同一操作,所以可以使用迭代器模式方便遍历。
  • 组合模式。由于鸭子集合可能会含有子集合和鸭子,并也需要支持上述行为,所以可以使用组合模式将鸭子和鸭子集合统一起来。
思考题

你能够有办法持续追踪个别鸭子的实时呱呱叫吗? P516

  • 观察者模式。题目意思就是鸭子在呱呱叫时通知观察人员,所以鸭子是可被观察的,应该继承 Observable 类,而观察人员应该实现 Observer 接口 ,观察人员在个别鸭子上注册以便实时接收鸭子的呱呱叫行为。
    • 按照以上设计会修改所有的鸭子类,所以就想到可以再加一个装饰器继承 Observable 类,并实现 Quackable 接口,这样改动量最小,不会改变原有鸭子类,也可以将鸭子和可被观察解耦。但想象很美好,一去实现就会遇到很多问题:用户代码必须与该装饰器耦合,需要特判该装饰器以执行注册观察者和通知观察者的方法;该装饰器只能最后包装,如果被其他装饰器包装就无法再调用相应方法;不便于将相应的方法扩展到组合模式中的集合上。所以还是需要接口上的修改,改变所有鸭子的行为。
    • 书上设计是让 Quackable 接口继承 QuackObservable 接口以便所有能叫的鸭子都能被观察;修改所有鸭子类,并将 Observable 类组合进鸭子类中,将注册观察者和通知观察者的方法内部委托到 Observable 相应的方法中;同时也要修改相应的装饰器。
思考题

我们还没有改变一个 Quackable 的实现,即 QuackCounter 装饰器。它也必须成为 Observable 。你何不试着写出它的代码呢? P518

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;
    }
    
    public void registerObserver(Observer observer) {
        duck.registerObserver(observer);
    }
    
    public void notifyObservers() {
        duck.notifyObservers();
    }
}
思考题

万一呱呱叫学家想观察整个群,又该怎么办呢?当观察某个组合时,就等于观察组合内的每个东西。 P520

public class Flock implements Quackable {
    ArrayList ducks = new ArrayList();
    
    public void add(Quackable duck) {
        ducks.add(duck);
    }
    
    public void quack() {
        Iterator iterator = ducks.iterator();
        while(iterator.hasNext()) {
            Quackable duck = (Quackable) iterator.next();
            duck.quack();
        }
    }
    
    public void registerObserver(Observer observer) {
        Iterator iterator = ducks.iterator();
        while(iterator.hasNext()) {
            Quackable duck = (Quackable) iterator.next();
            duck.registerObserver(observer);
        }
    }
    
    public void notifyObservers() {
        // 鸭群注册观察者都委托到孩子上了,所以通知观察者的事情并不需要鸭群做任何事
    }
}
所思所想
  • 可以通过让原有接口继承新接口的方式,再增加接口方法和相应的功能的同时,减少用户修改代码。例如:JDK7 中就让原有的 Closable 接口继承 AutoClosable 接口,使得原有的用户代码都不必修改就能在 JDK7中使用带资源的 try 语句能自动关闭资源的新特性。(第一次看见 AutoClosable 接口时,直接从语义上就认为 AutoClosable 继承了 Closable ,没想到正相反)

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

Head First设计模式》作者Eric Freeman;ElElisabeth Freeman是作家、讲师和技术顾问。本书的产品设计应用神经生物学、认知科学,以及学习理论,这使得这本书能够将这些知识深深地印在你的脑海里,不容易被遗忘。本书的编写方式采用引导式教学。以大量的生活化故事当背景,以图片做背景,阅读起来生动有趣。书中模式告白节目,将设计模式拟人化成节目来宾,畅谈其内在的一切。 《Head First设计模式(中文版)共有14章,每章都介绍了几个设计模式,完整地涵盖了四人组版本全部23个设计模式。前言先介绍这本书的用法;第1章到第11章陆续介绍的设计模式为Strategy、Observer、Decorator、Abstract Factory、Factory Method、Singleton,Command、Adapter、Facade、TemplateMethod、Iterator、Composite、State、Proxy。最后三章比较特别。第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式等主题,至于第14章则很快地浏览尚未介绍的设计模式,包括Bridge、Builder、Chain of Responsibility、Flyweight、Interpreter、Mediator、Memento、Prototype,Visitor。第1章还介绍了四个○○基本概念(抽象、封装、继承、多态),而第1章到第9章也陆续介绍了九个○○原则(Principle)。千万不要轻视这些○○原则,因为每个设计模式背后都包含了几个○○原则的概念。很多时候,在设计时有两难的情况,这时候我们必须回归到○○原则,以方便判断取舍。可以这么说:○○原则是我们的目标,而设计模式是我们的做法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值