模式通常会被一起使用,并被组合在同一个设计解决方案中。
复合模式在一个解决方案中结合两个或多个模式,以解决一般或者重复发生的问题。
一、 首先我们想建立一个鸭子模拟器
1. 首先我们创建一个Quackable接口:
// 接口
public interface Quackable {
public void quack();
}
2. 其次我们再实现某些鸭子:
// 标准绿头鸭
public class MallardDuck implements Quackable {
public void quack() {
System.out.println("MallarDuck Quack");
}
}
// 红头鸭
public class RedheadDuck implements Quackable {
public void quack() {
System.out.println("RedheadDuck Quack");
}
}
// 鸭鸣器
public class DuckCall implements Quackable {
public void quack() {
System.out.println("DuckCall Kwak");
}
}
// 橡皮鸭
public class RubberDuck implements Quackable {
public void quack() {
System.out.println("RubberDuck Squeak");
}
}
3. 创建鸭子模拟器
// 模拟器
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
public void simulator() {
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck();
Quackable duckCall = new DuckCall();
Quackable rubberDuck = new RubberDuck();
System.out.println("\nDuck Simulator");
simulator(mallardDuck);
simulator(redheadDuck);
simulator(duckCall);
simulator(rubberDuck);
}
public void simulator(Quackable duck) {
duck.quack();
}
}
4. 运行~
Duck Simulator
MallarDuck Quack
RedheadDuck Quack
DuckCall Kwak
RubberDuck Squeak
二、我们也想让模拟器兼容鹅
1. 创建鹅类
// 鹅来了
public class Goose {
public void honk() {
System.out.println("Goose Honk");
}
}
2. 鹅适配器
但是鹅不能直接扔进去模拟器里,因为类型不同,模拟器只接收实现Quackable接口的类,于是我们需要用到适配器模式将鹅适配成鸭子。
适配器模式:改写接口,将一个接口改成另一个接口以适应目标客户。
// 适配器模式,实现目标接口(Duckable)
public class GooseAdapter implements Quackable {
Goose goose;
public GooseAdapter(Goose goose) {
this.goose = goose;
}
// 调用quack()方法后,会被委托到鹅的honk()方法上
public void quack() {
goose.honk();
}
}
3. 在模拟器中使用鹅
// 新的模拟器
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
public void simulator() {
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("\nDuck Simulator");
simulator(mallardDuck);
simulator(redheadDuck);
simulator(duckCall);
simulator(rubberDuck);
simulator(gooseDuck); // 适配器实现了Quackable()接口,所以可以模拟
}
public void simulator(Quackable duck) {
duck.quack();
}
}
4. 运行结果(鹅也可以用了)
Duck Simulator
MallarDuck Quack
RedheadDuck Quack
DuckCall Kwak
RubberDuck Squeak
Goose Honk
三、有呱呱叫学者想统计一下鸭子叫了几声
1. 创建一个装饰者
不必修改鸭子代码,创建装饰者把鸭子包装起来,给鸭子一些新的行为。
装饰者模式:动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。
// 装饰者
public class QuackCounter implements Quackable{
Quackable duck;
static int numberOfQuacks;
public QuackCounter(Quackable duck) {
this.duck = duck;
}
// 给装饰者加入了一个静态方法,以便返回在所有Quackable中发生的叫声次数
public static int getQuacks() {
return numberOfQuacks;
}
public void quack() {
duck.quack();
numberOfQuacks++;
}
}
2. 更新此模拟器,以便创建被装饰的鸭子
// 修改模拟器
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
public void simulator() {
Quackable mallardDuck = new QuackCounter(new MallardDuck()); //修改的地方在这里,用装设者去包装鸭子
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("\nDuck Simulator");
simulator(mallardDuck);
simulator(redheadDuck);
simulator(duckCall);
simulator(rubberDuck);
simulator(gooseDuck);
System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times"); // 输出一下
}
public void simulator(Quackable duck) {
duck.quack();
}
3. 输出
Duck Simulator
MallarDuck Quack
RedheadDuck Quack
DuckCall Kwak
RubberDuck Squeak
Goose Honk
The ducks quacked 4 times
四、为什么要一个一个包装鸭子,万一漏了包装怎么办
我们可以用工厂生产鸭子,确保鸭子的质量
抽象工厂模式:定义一个抽象工厂类,多种类型的工厂继承它,并实例化具体方法,除了继承外另一个优点是可以把一群相关产品集合起来,但如果加入新产品就需要修改接口。
1. 定义一个抽象工厂,子工厂会创建不同的家族
// 抽象工厂
public abstract class AbstractDuckFactory {
public abstract Quackable createMallardDuck();
public abstract Quackable createRedheadDuck();
public abstract Quackable createDuckCall();
public abstract Quackable createRubberDuck();
}
2. 创建一个没有装饰者的鸭子
// 没有装饰者的鸭子
public class DuckFactory extends AbstractDuckFactory {
// 这样写,模拟器只知道是一种特定种类的Quackable,并不知道实际是什么。
public Quackable createMallardDuck() {
return new MallardDuck();
}
public Quackable createRedheadDuck() {
return new RedheadDuck();
}
public Quackable createDuckCall() {
return new DuckCall();
}
public Quackable createRubberDuck() {
return new RubberDuck();
}
}
3. 创建具有可以包装鸭子的工厂
public class CountingDuckFactory extends AbstractDuckFactory {
// 每个方法都会先会被装饰者包装起来
public Quackable createMallardDuck() {
return new QuackCounter(new MallardDuck());
}
public Quackable createRedheadDuck() {
return new QuackCounter(new RedheadDuck());
}
public Quackable createDuckCall() {
return new QuackCounter(new DuckCall());
}
public Quackable createRubberDuck() {
return new QuackCounter(new RubberDuck());
}
}
4. 要修改模拟器
// 改成用工厂去实例化
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulator(duckFactory);
}
public void simulator(AbstractDuckFactory duckFactory) {
Quackable mallardDuck = duckFactory.createMallardDuck(); // 用这种方法创建鸭子了,而不是直接实例化
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\nDuck Simulator");
simulator(mallardDuck);
simulator(redheadDuck);
simulator(duckCall);
simulator(rubberDuck);
simulator(gooseDuck);
System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times");
}
public void simulator(Quackable duck) {
duck.quack();
}
}
5. 运行喽
Duck Simulator
MallarDuck Quack
RedheadDuck Quack
DuckCall Kwak
RubberDuck Squeak
Goose Honk
The ducks quacked 4 times
五、为什么要管个别的鸭子
每次创建一个鸭子,一个一个管理太麻烦了,不如创建一个集合
1. 创建一群鸭子
组合模式允许我们像对待单个对象一样对待对象集合。
组合模式:通常以树形结构实现来表示“整体/部分”的层次结构,将组合和子节点实现统一的接口,从而达到对客户透明的目的。
// 组合和叶节点需要有同样的接口,这里的叶节点是Quackable
public class Flock implements Quackable {
List<Quackable> quackers = new ArrayList<Quackable>(); // 记录属于这个Flock的Quackable对象
public void add(Quackable quacker) {
quackers.add(quacker);
}
public void quack() {
Iterator<Quackable> itertor = quackers.iterator(); // 这里是迭代器模式
while(itertor.hasNext()) {
Quackable quacker = (Quackable)itertor.next();
quacker.quack();
}
}
}
迭代器模式:提供一个统一的接口可以顺序访问聚合对象中的元素,而不暴露其内部的表示
2. 再修改模拟器
public class DuckSimulator {
public static void main(String[] args) {
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulator(duckFactory);
}
public void simulator(AbstractDuckFactory duckFactory) {
Quackable redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
System.out.println("\nDuck Simulator: With composite = Flocks");
Flock flockOfDucks = new Flock(); // 创建许多个Flock,然后把Quackable塞给它,这是主群
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
flockOfDucks.add(gooseDuck);
Flock flockOfMallards = new Flock(); // 创建一个绿头鸭群
Quackable mallardOne = duckFactory.createMallardDuck(); // 创建小绿头鸭
Quackable mallardTwo = duckFactory.createMallardDuck();
Quackable mallardThree = duckFactory.createMallardDuck();
Quackable mallardFour = duckFactory.createMallardDuck();
flockOfMallards.add(mallardOne); // 塞给它很多小绿头鸭
flockOfMallards.add(mallardTwo);
flockOfMallards.add(mallardThree);
flockOfMallards.add(mallardFour);
flockOfDucks.add(flockOfMallards); // 绿头鸭加入主群
System.out.println("\nDuck Simulator: Whole Flock Simulation");
simulator(flockOfDucks); // 测试主群
System.out.println("\nDuck Simulator: Mallard Flock Simulation");
simulator(flockOfMallards); // 测试绿头鸭群
System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times");
}
public void simulator(Quackable duck) {
duck.quack();
}
}
3. 结果
Duck Simulator: With composite = Flocks
Duck Simulator: Whole Flock Simulation
RedheadDuck Quack
DuckCall Kwak
RubberDuck Squeak
Goose Honk
MallarDuck Quack
MallarDuck Quack
MallarDuck Quack
MallarDuck Quack
Duck Simulator: Mallard Flock Simulation
MallarDuck Quack
MallarDuck Quack
MallarDuck Quack
MallarDuck Quack
The ducks quacked 11 times
六、总结
这是一群模式携手合作,不是复合模式。复合模式是指一群模式被结合起来使用,以解决一般性问题。MVC(Model-View-Controller)复合模式。它是由数个模式结合起来而形成的新模式,一再地被用于解决许多设计问题。
并不是说遇到问题就一定要用设计模式来解决,杀鸡焉用牛刀。有时用好的OO设计原则可以解决就可以解决问题。