该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!
复合模式:
模式的模式;
本章主要介绍如何使用多种模式解决具体问题,以及复合模式的代表MVC的使用;
模式通常被一起使用,并被组合在同一个设计解决方案中;
复合模式在一个解决方案中结合两个或多个模式,已解决一般或重复发生的问题;
鸭子模拟器示例:
一堆Quackable,会叫的鸭子;
出现一只鹅,他希望自己像个Quackable;
呱呱叫学家决定要计算呱呱叫声的次数;
担心忘记给Quackable加上QuackCounter装饰者怎么办;
又是鸭子、又是鹅、又是Quackable…….管理上的困扰;
任何呱呱叫时,呱呱叫学家都希望能被告知;
接下来看如何使用设计模式解决上述问题:
1.设计创建一个Quackable接口:
【Code-Quackable.java】
public interface Quackable{
public void quack();
}
2.设计一些具体的鸭子实现Quackable接口:
【Code-Demo1Duck.java】
public class Demo1Duck implements Quackable{
public void quack(){
System.out.println("Quack!");
}
}
【Code-Demo2Duck.java】
public class Demo2Duck implements Quackable{
public void quack(){
System.out.println("Quack!");
}
}
【Code-Demo3Duck.java】
public class Demo3Duck implements Quackable{
public void quack(){
System.out.println("Quack!");
}
}
加入了鸭鸣器和橡皮鸭,他们的叫声有些不同:
【Code-Duckcall.java】
public class Duckcall implements Quackable{
public void quack(){
System.out.println("Kwak!");
}
}
【Code-RubberDuck.java】
public class RubberDuck implements Quackable{
public void quack(){
System.out.println("Squeak!");
}
}
3.新建鸭子模拟器:
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
void simulator(){
Quackable demo1Duck = new Demo1Duck();
Quackable demo2Duck = new Demo2Duck();
Quackable demo3Duck = new Demo3Duck();
Quackable duckcall = new Duckcall();
Quackable rubberDuck = new RubberDuck();
simulator(demo1Duck);
simulator(demo2Duck);
simulator(demo3Duck);
simulator(duckcall);
simulator(rubberDuck);
}
void simulator(Quackable duck){
duck.quack();
}
}
运行:
bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
4.鹅也出现了:鹅是“咯咯”叫;
【Code-Goose.java】
public class Goose {
public void honk(){
System.out.println("Honk!!");
}
}
5.想要在鸭子模拟器中使用鹅,我们需要鹅适配器:
【Code-GooseAdapter.java】
public class GooseAdapter implements Quackable{
Goose goose;
public GooseAdapter(Goose goose){
this.goose = goose;
}
public void quack(){
goose.honk();
}
}
6.这样我们就可以在鸭子模拟器中使用鹅了:
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
void simulator(){
Quackable demo1Duck = new Demo1Duck();
Quackable demo2Duck = new Demo2Duck();
Quackable demo3Duck = new Demo3Duck();
Quackable duckcall = new Duckcall();
Quackable rubberDuck = new RubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
simulator(demo1Duck);
simulator(demo2Duck);
simulator(demo3Duck);
simulator(duckcall);
simulator(rubberDuck);
simulator(gooseDuck);
}
void simulator(Quackable duck){
duck.quack();
}
}
7.运行:
bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
8.一群鸭子中有多少呱呱叫声,我们要让呱呱叫学着知道叫声的次数:
我们创建一个装饰者,将鸭子包装进装饰者对象,给鸭子添加一些新的行为(计算次数),不必修改鸭子代码;
【Code-QuackCounter.java】
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;
}
}
9.我们需要更新此模拟器,以便创建被装饰的鸭子:
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
simulator.simulator();
}
void simulator(){
Quackable demo1Duck = new QuackCounter(new Demo1Duck());
Quackable demo2Duck = new QuackCounter(new Demo2Duck());
Quackable demo3Duck = new QuackCounter(new Demo3Duck());
Quackable duckcall = new QuackCounter(new Duckcall());
Quackable rubberDuck = new QuackCounter(new RubberDuck());
Quackable gooseDuck = new GooseAdapter(new Goose());
simulator(demo1Duck);
simulator(demo2Duck);
simulator(demo3Duck);
simulator(duckcall);
simulator(rubberDuck);
simulator(gooseDuck);
System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
}
void simulator(Quackable duck){
duck.quack();
}
}
运行:
bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Ducks quacked 5 times.
10.只有装饰过的鸭子叫才会被统计,最好将创建鸭子的行为集中-可以用工厂生产鸭子:
我们创建一个工程,生产装饰过的鸭子,为产生不同类型的鸭子的产品家族,需要抽象工厂模式;
【Code-AbstractDuckFactory.java】
public abstract class AbstractDuckFactory{
//每种方法创建一种鸭子
public abstract Quackable createDemo1Duck();
public abstract Quackable createDemo2Duck();
public abstract Quackable createDemo3Duck();
public abstract Quackable createDuckcall();
public abstract Quackable createRubberDuck();
}
创建一个工厂-生产普通鸭子:
【Code-DuckFactory.java】
public class DuckFactory extends AbstractDuckFactory{
//每种方法创建一种鸭子
public Quackable createDemo1Duck(){
return new Demo1Duck();
}
public Quackable createDemo2Duck(){
return new Demo2Duck();
}
public Quackable createDemo3Duck(){
return new Demo3Duck();
}
public Quackable createDuckcall(){
return new Duckcall();
}
public Quackable createRubberDuck(){
return new RubberDuck();
}
}
创建一个工厂-生产装饰过计数行为的鸭子:
【Code-CountingDuckFactory.java】
public class CountingDuckFactory extends AbstractDuckFactory{
//每种方法创建一种鸭子
public Quackable createDemo1Duck(){
return new QuackCounter(new Demo1Duck());
}
public Quackable createDemo2Duck(){
return new QuackCounter(new Demo2Duck());
}
public Quackable createDemo3Duck(){
return new QuackCounter(new Demo3Duck());
}
public Quackable createDuckcall(){
return new QuackCounter(new Duckcall());
}
public Quackable createRubberDuck(){
return new QuackCounter(new RubberDuck());
}
}
11.设置模拟器来使用这个工厂(CountingDuckFactory):
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulator(duckFactory);
}
void simulator(AbstractDuckFactory duckFactory){
Quackable demo1Duck = duckFactory.createDemo1Duck();
Quackable demo2Duck = duckFactory.createDemo2Duck();
Quackable demo3Duck = duckFactory.createDemo3Duck();
Quackable duckcall = duckFactory.createDuckcall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
simulator(demo1Duck);
simulator(demo2Duck);
simulator(demo3Duck);
simulator(duckcall);
simulator(rubberDuck);
simulator(gooseDuck);
System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
}
void simulator(Quackable duck){
duck.quack();
}
}
运行:
bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Ducks quacked 5 times.
12.将鸭子视作一个集合(子集合),管理员想要管理所有的鸭子:
创建一群鸭子(一群Quackable),使用组合模式像对单个对象一样对待对象集合;
组合节点:【Code-Flock.java】,叶子节点就是具体的鸭子;
import java.util.*;
public class Flock implements Quackable{
ArrayList<Quackable> quackers = new ArrayList<Quackable>();
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();
}
}
}
13.修改模拟器 让鸭子进入组合结构:(注意透明性和安全性之间的权衡)
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulator(duckFactory);
}
void simulator(AbstractDuckFactory duckFactory){
Quackable demo1Duck = duckFactory.createDemo1Duck();
Quackable demo2Duck = duckFactory.createDemo2Duck();
Quackable demo3Duck = duckFactory.createDemo3Duck();
Quackable duckcall = duckFactory.createDuckcall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
Flock flockOfDucks = new Flock();
flockOfDucks.add(demo1Duck);
flockOfDucks.add(demo2Duck);
flockOfDucks.add(demo3Duck);
Flock flockOfAllDucks = new Flock();
flockOfAllDucks.add(flockOfDucks);
flockOfAllDucks.add(duckcall);
flockOfAllDucks.add(rubberDuck);
flockOfAllDucks.add(gooseDuck);
simulator(flockOfAllDucks);//test all ducks
simulator(flockOfDucks);//test part normal ducks
System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
}
void simulator(Quackable duck){
duck.quack();
}
}
运行:
bogon:鸭子模拟器 huaqiang$ javac *.java -Xlint:unchecked
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Quack!
Quack!
Quack!
Ducks quacked 8 times.
14.现在,有什么办法让我们能持续追踪个别鸭子的实时呱呱叫吗?—— 可以使用观察者模式;
我们需要一个Observable接口:
Observable是被观察者的对象,需要注册和通知观察者的方法;(为了简单这里省略了移除观察者的方法)
QuackObservable是一个接口,任何想被观察的Quackable都必须实现QuackObservable接口;
【Code-QuackObservable.java】
public interface QuackObservable {
public void registerObserver(Observer observer);
public void notifyObservers();
}
接下来让所有的Quackable都实现此接口:直接让Quackable扩展自此接口;
【Code-Quackable.java】
public interface Quackable extends QuackObservable{
public void quack();
}
15.由于让Quackable扩展自QuackObservable,导致所有的Duck都需要实现QuackObservable接口定义的API;
为了使用一份代码,我们新建一个实现QuackObservable接口的辅助类Observable,每一个Duck都将各自实现的QuackObservable接口API委托给Observable辅助类:
【Code-Observable.java】
import java.util.*;
public class Observable implements QuackObservable{
ArrayList<Observer> observers = new ArrayList<Observer>();
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);
}
}
}
16.现在需要修改众多Quackable类,使用辅助类Observable:
【Code-Demo1Duck.java】
public class Demo1Duck implements Quackable{
Observable observable;
public Demo1Duck(){
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();
}
}
【Code-Demo2Duck.java】
public class Demo2Duck implements Quackable{
Observable observable;
public Demo2Duck(){
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();
}
}
【Code-Demo3Duck.java】
public class Demo3Duck implements Quackable{
Observable observable;
public Demo3Duck(){
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();
}
}
【Code-Duckcall.java】
public class Duckcall implements Quackable{
Observable observable;
public Duckcall(){
observable = new Observable(this);
}
public void quack(){
System.out.println("Kwak!");
notifyObservers();
}
public void registerObserver(Observer observer){
observable.registerObserver(observer);
}
public void notifyObservers(){
observable.notifyObservers();
}
}
【Code-RubberDuck.java】
public class RubberDuck implements Quackable{
Observable observable;
public RubberDuck(){
observable = new Observable(this);
}
public void quack(){
System.out.println("Squeak!");
notifyObservers();
}
public void registerObserver(Observer observer){
observable.registerObserver(observer);
}
public void notifyObservers(){
observable.notifyObservers();
}
}
【Code-GooseAdapter.java】
public class GooseAdapter implements Quackable{
Goose goose;
Observable observable;
public GooseAdapter(Goose goose){
this.goose = goose;
observable = new Observable(this);
}
public void quack(){
goose.honk();
notifyObservers();
}
public void registerObserver(Observer observer){
observable.registerObserver(observer);
}
public void notifyObservers(){
observable.notifyObservers();
}
}
【Code-QuackCounter.java】
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();
}
}
【Code-Flock.java】
import java.util.*;
public class Flock implements Quackable{
ArrayList<Quackable> quackers = new ArrayList<Quackable>();
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();
}
}
public void registerObserver(Observer observer){
Iterator iterator = quackers.iterator();
while(iterator.hasNext()){
Quackable quacker = (Quackable)iterator.next();
quacker.registerObserver(observer);
}
}
public void notifyObservers(){
Iterator iterator = quackers.iterator();
while(iterator.hasNext()){
Quackable quacker = (Quackable)iterator.next();
quacker.notifyObservers();
}
}
}
17.我们已经使用了Observer,现在我们要做的就是把Observer端完成:
包括Observer接口和一些观察者;
【Code-Observer.java】
public interface Observer{
public void update(QuackObservable duck);
}
【Code-Quackologist.java】
public class Quackologist implements Observer{
public void update(QuackObservable duck){
System.out.println("Quackologist:" + duck + " just quacked.");
}
}
值得注意的是:现在如果想观察一组鸭子也很方便,直接观察一个Flock就行了;
18.更新模拟器:
【Code-DuckSimulator.java】
public class DuckSimulator{
public static void main(String[] args){
DuckSimulator simulator = new DuckSimulator();
AbstractDuckFactory duckFactory = new CountingDuckFactory();
simulator.simulator(duckFactory);
}
void simulator(AbstractDuckFactory duckFactory){
Quackable demo1Duck = duckFactory.createDemo1Duck();
Quackable demo2Duck = duckFactory.createDemo2Duck();
Quackable demo3Duck = duckFactory.createDemo3Duck();
Quackable duckcall = duckFactory.createDuckcall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
Flock flockOfDucks = new Flock();
flockOfDucks.add(demo1Duck);
flockOfDucks.add(demo2Duck);
flockOfDucks.add(demo3Duck);
Flock flockOfAllDucks = new Flock();
flockOfAllDucks.add(flockOfDucks);
flockOfAllDucks.add(duckcall);
flockOfAllDucks.add(rubberDuck);
flockOfAllDucks.add(gooseDuck);
Quackologist quackologist = new Quackologist();
flockOfDucks.registerObserver(quackologist);
simulator(flockOfAllDucks);//test all ducks
simulator(flockOfDucks);//test part normal ducks
System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
}
void simulator(Quackable duck){
duck.quack();
}
}
运行:
bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quackologist:Demo1Duck@7852e922 just quacked.
Quack!
Quackologist:Demo2Duck@4e25154f just quacked.
Quack!
Quackologist:Demo3Duck@70dea4e just quacked.
Kwak!
Squeak!
Honk!!
Quack!
Quackologist:Demo1Duck@7852e922 just quacked.
Quack!
Quackologist:Demo2Duck@4e25154f just quacked.
Quack!
Quackologist:Demo3Duck@70dea4e just quacked.
Ducks quacked 8 times.
我们发现,每次被观察的鸭子叫时,都会通知观察者;
上述代码结构类图:
复合模式之王:
Model-View-Controller(模型-视图-控制器)模式;
MVC是一种泛型,它构造代码成为功能段,达到复用的目的;
视图对象通常是控件,用来显示和编辑;但视图并不知道模型;视图和模型之间的数据流通是由控制器居中协调进行的;
MVC是由数个设计模式结合起来的模式;
认识MVC(播放器示例):
有的时候,控制器也可以直接向模型注册观察者,继而改变视图的显示(即第4步是由控制器指向模型的);
MVC的组成:
模型利用观察者让控制器和视图可以随最新的状态改变和更新;
视图和控制器实现了策略模式,控制器是视图的行为,如果希望不同行为,可以换一个控制器;
视图内部使用组合模式来管理窗口、按钮以及其他显示组件;
视图是一个对象,可以被调整使用不同的策略,而控制器提供了策略;
视图只关心可视的部分,将行为委托给控制器处理,策略模式使得视图和模型之间的关系解耦,因为控制器负责和模型交互来传递用户的请求;视图并不知道工作如何完成;
模型对视图和控制器没有依赖;
模型实现应用逻辑,并决定如何响应动作;
控制器也做一些决定,决定调用哪个模型的哪个方法;但这不算应用逻辑;
应用逻辑指的是管理和操纵你的模型中的数据的代码;
有人吧MVC的控制器描述为视图和模型的中介者:
中介者的意图是封装对象之间的交互,不让两个对象之间互相显示引用,以达到松耦合的目的;
某种程度上,控制器可以被视为中介者:视图通过控制器设置模型状态,也通过控制器获取模型状态;
总结:
1.MVC是复合模式,结合了观察者、策略模式和组合等模式;
2.模式使用观察者模式,以便观察者更新,同时保持两者间解耦;
3.控制器是视图的策略,视图可以使用不同的控制器,得到不同的行为;
4.视图使用组合模式实现,用户界面通常嵌套组件;
5.这些模式一起,完成MVC三层解耦,保持设计干净又有弹性;
6.适配器模式用来将新的模型是配成已有的视图和控制器;
OO基础:
抽象;
封装
继承;
多态;
OO原则:
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程
为交互对象之间的松耦合设计而努力;
类应该对扩展开放,对修改关闭;
依赖抽象,不要依赖具体类;
只和朋友交谈(最少知识原则);
别找我,我会找你(好莱坞原则:由超类主控一切,需要的时候自然会去调用子类);
类应该只有一个改变的理由(单一职责原则);
OO模式:
策略模式:定义算法族,分别封装起来,让他们之间互相替换,此模式让算法的变化独立于使用算法的客户;
观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新;
装饰者模式:动态地将责任附加到对象上;想要扩展功能,装饰者提供有别于继承的另一种选择;
简单工厂模式;
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个;工厂方法让类把实例化推迟到子类;
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确具体的类;
单件模式:确保一个类只有一个实例,并提供全局访问点;
命令模式:将请求封装成对象,这可以让你使用不同的请求,队列或者日志请求来参数化其他对象;命令模式也支持撤销操作;
适配器模式:将一个类的接口转换成客户期待的另一个接口,适配器让原来不兼容的类可以合作无间;
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口;外观模式定义了高层接口,让子系统更容易使用;
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中;模板方法使得子类可以在不改变算法结构的情况下,重新定义/捕获算法中的某些步骤;
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示;
组合模式:允许你将对象组成树形结构来表现整体/部分的层次结构;组合能让客户以一致的方式处理个别对象和对象组合;
状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了它的类;
代理模式:为另一个对象提供一个替身或占位符以访问这个对象;
——复合模式:结合两个或两个以上的模式,组成一个解决方案,解决一再发生的一般性问题;