《Headfirst设计模式》学习笔记

策略模式

  1. 封装变化。找出应用中可能需要变化之处,把他们独立出来,不用和那些不需要变化的代码混在一起。把变化的行为单独建立一个抽象类及对应的派生类。
  2. 针对接口(抽象类)编程而不是针对实现编程。这里的接口泛指实现某个超类型的某个方法。
  3. 动态设定行为。建立set函数传入欲修改的数据成员。
  4. 多用组合,少用继承。将变化的行为所构成的抽象类设定为数据成员并在派生类的构造函数中new一个相应的行为类。

策略模式 定义了算法族(每组行为),分别封装起来,让让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
以下所有代码均为伪代码,其中abstract纯粹是为了说明类是抽象的

//所以我们把鸭子的飞行为和叫行为这两个变化行为分离封装起来
//抽象鸭子类
abstract class Duck{
public:
    //多用组合少用继承
    FlyBehavior* flyWay;
    QuackBehavior* quackWay;
    //鸭子的描述
    virtual void display()=0;
    //执行飞这个行为
    void performFly(){
        flyWay.fly();
    }
    //执行叫这个行为
    void performQuack(){
        quackWay.quack();
    }
    //动态设定飞行为
    void setFlyBehavior(FlyBehavior newFlyWay){
        flyWay=newFlyWay;
    }
    //动态设定叫行为
    void setQuackBehavior(QuackBehavior newQuackWay){
        quackWay=newQuackWay;
    }
};
//飞行为抽象
abstract class FlyBehavior{
public:
    virtual void fly()=0;
};
//叫行为抽象
abstract class QuackBehavior{
public:
    virtual void quack()=0;
};
//模型鸭(不会飞,guagua叫)
class ModelDuck:public Duck{
public:
    ModelDuck(){
        //不能飞
        flyWay=new FlyNoWay();
        //guagua叫
        quackWay=new GuaGua();
    }
    void display(){
        cout<<"I'm a model duck"<<endl;
    }
};
//不能飞行为
class FlyNoWay:public FlyBehavior{
public:
    void fly(){
        cout<<"I can't fly"<<endl;
    }
};
//guagua叫行为
class GuaGua:public QuackBehavior{
public:
    void quack(){
        cout<<"guagua"<<endl;
    }
};
//测试代码
void main(){
    Duck model=new ModelDuck();
    model.performFly();
    model.performQuack();
}

观察者模式

主题+观察者
主题对象管理某些数据,当主题内的数据改变时就会通知观察者,当观察者已经注册主题时便能够收到更新。观察者可以申请加入或退出主题。
观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
一个主题接口应该包括registerObserver、removeObserver、notifyObserver即注册、撤销、通知观察者三个方法以及getState、setState即设置和获取状态的方法。
一个观察者接口只需包含update方法即可,用于主题状态改变时接收更新。
在观察者模式中,主题是具有状态的对象,并且可以控制这些状态,观察者只能使用这些状态,主题是真正拥有数据的人,观察者是主题的依赖者。另一方面,主题只知道观察者实现了某个接口,主题不需要知道观察者的具体类是谁。如此一来有新类型的观察者出现时,主题的代码不需要修改,我们可以独立地复用主题或观察者,改变主题或观察者其中一方,并不会影响另一方。这被称为松耦合

  1. 交互对象之间应该满足松耦合条件。
//主题抽象类
abstract class Subject{
public:
    //观察者注册
    virtual void registerObserver(Observer o)=0;
    //观察者注销
    virtual void removeObserver(Observer o)=0;
    //向观察者发送通知
    virtual void notifyObservers()=0;
};
//观察者类
abstract class Observer{
public:
    //观察者只需要实现当主题发来通知时更新自己的内容
    //info表示观察者接受的参数
    virtual void update(vars info)=0;
};

装饰者模式

  1. 类应该对扩展开放,对修改关闭

装饰者模式 动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

装饰者与被装饰对象(即被包装的组件)有相同的超类型。但装饰者与组件组合时是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。

//基础组件抽象类
abstract class BaseElement{
public:
    //基础花费类
    virtual double cost()=0;
};
//基础组件One类
class BaseOne:public BaseElement{
public:
    //基础组件One需要的花费
    double cost(){
        return 1;
    }
};
//装饰者One类
class DecorateOne:public BaseElement{
public:
    //要修饰的组件
    BaseElement base;
    //构造函数
    DecorateOne(BaseElement newBase){
        this.base=newBase;
    }
    //装饰后的花费,假设装饰One本身默认花费为10
    double cost(){
        return 10+base.cost();
    }
};
//装饰者Two类
class DecorateTwo:public BaseElement{
public:
    //要修饰的组件
    BaseElement base;
    //构造函数
    DecorateTwo(BaseElement newBase){
        this.base=newBase;
    }
    //装饰后的花费,假设装饰Two本身默认花费为20
    double cost(){
        return 20+base.cost();
    }
};
//装饰过程
void main(){
    //基础组件只能有一个,这里选择组件One,但可以对此组件多重装饰
    BaseElement* result=new BaseOne();
    //用One装饰者装饰
    result=new DecorateOne(result);
    //用Two装饰者装饰
    result=new DecorateTwo(result);
    //返回多重装饰后总的花费
    cout<<result.cost()<<endl;
}

工厂模式

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。

abstract Product factoryMethod(String type)
abstract:工厂方法是抽象的,必须依赖子类来处理对象的创建
Product:工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值
factoryMethod:工厂方法将客户(也就是超类中的代码)和实际创建具体产品的代码分隔开来
type:工厂方法可以使用参数来指定所要的产品

工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

创建者类:
抽象创建者类定义了一个抽象的工厂方法,让子类实现此方法制造产品。
创建者通常会包含依赖子抽象产品的代码,而这些抽象产品由子类制造。创建者不需要真的知道在制造哪种具体产品。
能够生产产品的类称为具体创建者。
产品类:
具体的产品。

工厂方法模式 定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

  1. 依赖倒置原则:要依赖抽象,不要依赖具体类
    指导方针:
    变量不可以持有具体类的引用(避免直接使用new)
    不要让类派生自具体类(派生自抽象—–接口或抽象类)
    不要覆盖基类中已实现的方法(基类中已实现的方法,应该由所有的子类共享)

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。

//工厂抽象类
abstract class Factory{
public:
    //工厂利用原料生产产品
    virtual Source createOne()=0;
    virtual Source createTwo()=0;   
};
//产品抽象类
abstract class Product{
public:
    //每个产品由多种原料组成
    Source one; 
    Source two; 
    //产品需要加工
    virtual void prepare()=0;
};
//商店抽象类
abstract class Store{
public:
    //商店购买商品type
    Product orderProduct(String type){
        //从工厂获取商品
        Product production=createProduct(type);
        //产品加工
        production.prepare();
        //给顾客商品
        return production;
    }
protected:
    //工厂方法生产出产品
    virtual Product createProduct(String type)=0;
};
//最近的工厂类
class NearFactory:public Factory{
public:
    Source* createOne(){
        //返回产地最近的原料1
        return nearOne;
    }
    Source* createTwo(){
        //返回产地最近的原料2
        return nearTwo;
    }   
};
//受欢迎的产品类
class PopularProduct:public Product{
public:
    Factory realFactory;
    //产品是由特定工厂生产的
    PopularProduct(Factory fac){
        this.realFactory=fac;
    }
    //产品加工
    void prepare(){
        one=realFactory.createOne();
        two=realFactory.createTwo();
    }
};
//楼下的商店类
class DownstairStore:public Store{
public:
    Product* createProduct(String type){
        if(type.equals("popular"){
            //若顾客选择的是受欢迎的产品,则返回由最近工厂出厂的商品(假设最近工厂的最好)
            return new PopularProduct(new NearFactory);
        }
    }
};
//顾客购买商品过程
void main(){
    DownstairStore *myfavorite=new DownstairStore();
    myfavorite.orderProduct("popular");
    //好了,这下可以吃我的薯片了
}

单件模式

单件模式 确保一个类只有一个实例,并提供一个全局访问点。

class Singleton{
private:
    static Singleton *uniqueInstance;   
    //声明唯一的实例为静态私有的
    Singleton(){}
    //声明构造函数为私有的保证只有一个实例
public:
    //公开getInstance函数使用户只能通过它获取唯一的实例
    //声明为静态的保证不用实例化对象即可获取唯一实例
    static Singleton getInstance(){
        if(uniqueInstance==NULL){
            //若尚未生成实例则在getInstance里生成唯一实例
            //也可以在类外声明唯一实例,则不用在函数里判断是否为空
            uniqueInstance=new Singleton();
        }
        return uniqueInstance;
    }
};

命令模式

命令模式 将“请求”封装成对象,一般使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。

命令模式将发出请求的对象和执行请求的对象解耦,在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收的和一个或一组动作。

类图:
Client:客户创建一个ConcreteCommand,并设置其接收者
Invoker:调用者持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸实行
Command:命令接口调用命令对象的execute()方法让接收者执行相关动作,调用undo()方法撤销之前执行的动作
Receiver:接收者知道如何进行必要的工作,实行这个请求,任何类都可以当接收者
ConcreteCommand:定义动作和接收者之间的绑定关系,调用者只需调用execute()方法就可以发出请求,然后由ConcreteCommand调用接收者的一个或多个动作

//遥控器控制灯光开关
//命令接口
abstract class Command{
public:
    virtual void execute()=0;
    virtual void undo()=0;
};
//打开灯光命令(ConcreteCommand)
class LightOnCommand:public Command{
public:
    Light lamp;
    LightOnCommand(Light newLamp):lamp(newLamp){}
    void execute(){
        //打开灯光命令执行后灯光打开
        lamp.on();
    }
    void undo(){
        //打开灯光命令撤销表示灯光应该关闭
        lamp.off();
    }
};
//遥控器(调用者Invoker)
class Remote{
public:
    Command button;
    void setCommand(Command newButton){
        //按钮绑定命令
        button=newButton;
    }   
    void pressed(){
        //按下按钮后命令执行
        button.execute();
    } 
    void clear(){
        //撤销按钮行为后命令撤销
        button.undo();
    }
};
//使用遥控器打开灯光
void main(){
    //客户(Client)创建一个遥控器
    Remote *control=new Remote();
    //定义一个灯泡(接收者Receiver)
    Light *lamp=new Light();
    //绑定开灯命令到灯泡
    LightOnCommand *onLight=new LightOnCommand(lamp);
    //绑定开关到遥控器
    control.setCommand(onLight);
    //按下开灯命令
    control.pressed();
}

命令可以将运算快打包(一个接收者和一组动作),然后将它传来传去,就像是一般的对象一样。
可以用在队列请求中:比如有一个工作队列,一端用于添加命令,另一端则是线程。线程执行从队列中取出一个命令,调用它的execute()方法,等待这个调用完成,然后将此命令对象丢弃,再取出下一个命令。工作队列对象无需在乎到底在做什么,只需要知道取出命令对象,然后调用其execute()方法。
日志请求:我们执行命令时将历史记录存储在磁盘中,一旦系统死机,我们就可以将命令对象重新加载,并成批地依次调用这些对象的execute()方法。
宏命令:制造一种命令用于执行其他一堆命令。

class MacroCommand:public Command{
public:
    Command[] buttons;
    MacroCommand(Command[] newButtons):buttons(newButtons){}
    void addCommand(Command addButton){
        \\buttons.push_back(addButton);
    }
    void execute(){
        for(int i=0;i<buttons.length;i++){
            buttons.execute();
        }
    }
};

适配器模式

客户使用适配器过程:
1. 客户通过目标接口调用适配器的方法对适配器发出请求
2. 适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口
3. 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用

适配器模式 将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

//实现火鸡转换成鸭子的适配器
//鸭子接口(目标接口)
abstract class Duck{
public:
    virtual void quack()=0;
    virtual void fly()=0;
};
//火鸡接口(被适配者接口)
abstract class Turkey{
public:
    virtual void gobble()=0;
    virtual void fly()=0;
};
//对象适配器(被适配者组合进适配器)
class TurkeyToDuck:public Duck{
public:
    Turkey tur;
    TurkeyToDuck(Turkey newTur):tur(newTur){}
    void quack(){
        tur.gobble();
    }
    void fly(){
        //火鸡连续飞5次才相当于鸭子飞一次
        for(int i=0;i<5;i++){
            tur.fly();
        }
    }
};
//类适配器(适配器多重继承被适配者和目标)
class TurkeyTranferDuck:public Duck,Turkey{
public:
    //覆盖Duck类中的quack方法
    void Duck::quack(){
        Turkey::gobble();
    }
    //覆盖Duck类中的fly方法
    void Duck::fly(){
        //火鸡连续飞5次才相当于鸭子飞一次
        for(int i=0;i<5;i++){
            Turkey::fly();
        }
    }
};
//客户需要把火鸡转换成鸭子
void main(){
    //野火鸡是火鸡的一种
    WileTurkey* wtur=new WileTurkey();
    //需要一个火鸡-鸭子的适配器
    Duck* adapter=new TurkeyToDuck();
    //让火鸡执行鸭子的动作
    adapter.quack();
    adapter.fly();
}

外观模式

外观模式的目的在于简化接口
外观并没有“封装”子系统的类,外观只提供简化的接口,客户仍然可以直接使用子系统的类。
外观可以新增功能,也可以为一个子系统创建多个外观
外观允许客户从子系统中解耦

外观模式 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

//子系统先执行的组件
class FirstElement{
public:
    void on(){//组件打开}
    void off(){//组件关闭}
};
//子系统2组件
class SecondElement{
public:
    void run(){//组件运行}
    void close(){//组件关闭}
};
//子系统外观
class Facade{
public:
    FirstElement ele;
    SecondElement mod;
    Facade(FirstElement newEle,SecondElement newMod):ele(newEle),mod(newMod){}
    //组件行为整合成统一行为
    void begin(){
        ele.on();
        mod.run();
    }
    void end(){
        mod.close();
        ele.off();
    }
};
  1. 最少知识原则(Law of Demeter墨忒耳法则):减少对象之间的交互,只留下几个“密友”并只和“密友”交互。
    原则在于在设计中不要让太多的类耦合在一起,避免修改系统中的一部分会影响到其它部分。

最少知识原则方针:
就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件

注意如果某对象是调用其它的方法的返回结果,不要调用该对象的方法!如果我们这样做,相当于向另一个对象的子部分发请求从而增加我们之间认识的对象数目,此时我们应该改为要求改对象为我们做出请求。

//原示例
int getTemp(){
    AClass temp=station.getAClass();
    return temp.getNumber();
}
//采用最少知识原则
int getTemp(){
    return station.getNumber();
}
//汽车类示例
class Car{
public:
    Engine eng;
    Car(){}
    void Start(Key mykey){
        Doors* gate=new Doors();
        //被当做参数传进来的对象,其方法可以被调用
        bool authorized=key.turns();
        if(authorized){
            //可以调用对象组件的方法
            engine.start();
            //可以调用同一个对象内的本地方法
            boardDisplay();
            //可以调用创建或实例化的对象的方法
            gate.lock();
        }
    }
    void boardDisplay(){//仪表盘打开}
};

缺点:会导致更多的“包装”类被制造出来,以处理和其它组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。

模版方法模式

模版方法模式 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模版 是一个方法,该方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。模版方法被声明成final,以免子类改变这个算法的顺序。

//包含模版方法的抽象类
abstract class TemplateClass{
public:
    //模版方法,具体子类得为模版方法算法中未定义的步骤提供完整的实现
    void templateMethod() final{
        primitiveOperationOne();
        primitiveOperationTwo();
        concreteOperation();
        hook();
    }
    //必须由具体子类实现的抽象方法
    virtual void primitiveOperationOne()=0;
    virtual void primitiveOperationTwo()=0;
    //不能让子类覆盖但模版方法或子类可以直接使用
    void concreteOperation() final{//具体方法}
    //“钩子”,被声明在抽象类中,只有空或默认的实现
    //钩子由子类决定要不要覆盖,从而有机会对模版方法中某些即将发生的步骤做出反应
    void hook(){//空的实现或定义一个默认的实现}
};
  1. 好莱坞原则:底层组件将自己挂钩在系统上,但由高层组件决定什么时候和怎样使用这些底层组件。

策略模式:

定义一个算法族,并让这些算法可以互换
通过对象组合方式

模版方法模式:

定义一个算法大纲,由子类定义其中某些步骤的内容
除少部分内容外,其余部分都是相同的
使用继承进行算法的实现

迭代器模式

迭代器是用来封装“遍历集合内每个对象的过程”的一个对象。

迭代器模式 提供一种方法顺序访问一个聚合(即集合)对象中的每个元素,而又不暴露其内部的表示。

迭代器模式把在元素间游走的责任交给迭代器,而不是聚合对象。
迭代器没有次序,它只是取出所有元素,并不表示取出元素的先后就代表元素的大小次序。

迭代器模式类图

Iterator:迭代器接口,包含一些可以在集合元素间游走的方法。
ConcreteIterator:具体迭代器负责管理目前遍历的位置
Aggregate:聚合类接口,将客户代码从集合对象的实现解耦
ConcreteAggregate:具体聚合持有一个对象的集合,并实现创建集合的迭代器的方法。

每一个具体的迭代器都要负责实例化一个具体迭代器,此迭代器能够遍历对象集合。

//迭代器接口
abstract class Iterator{
public:
    //判断是否还有更多的元素
    virtual bool hasNext()=0;
    //返回元素
    virtual Object next()=0;
};
//聚合类接口
abstract class Aggregate{
public:
    //聚合类只需要实现创建迭代器方法
    virtual Iterator createIterator()=0;
};
//数组型类的迭代器
class ArrayIterator:public Iterator{
public:
    //记录元素的数组
    Object[] items;
    //当前数组遍历的位置
    int position=0;
    //构造函数
    ArrayIterator(Object[] newItems):items(newItems){}
    //返回下一个元素
    Object next(){
        return items[position++];
    }
    //判断有无下一个元素
    bool hasNext(){
        //若越界或位置处无有效元素,返回false
        if(position>=items.length || items[position]==NULL){
            return false;
        }else{
            return true;
        |
    }
};
//某利用数组记录元素的类
class ArrayClass{
public:
    Object[] elements;
    //其它函数
    //...
    //创建迭代器方法
    Iterator createIterator(){
        return new ArrayIterator(elements);
    }
};
//使用迭代器
void main(){
    ArrayClass arr;
    Iterator it=arr.createIterator();
    //客户无需关心arr中的元素是数组型的还是vector,list型的
    //客户只需要调用hasNext()判断有无下一个元素,再用next()取出下一个元素即可
    while(it.hasNext()){
        print(it.next());
    }
}
//空迭代器
class NULLIterator:public Iterator{
public:
    Object next(){
        return NULL;
    }
    bool hasNext(){
        return false;
    }
};
  1. 单一责任原则:一个类应该只有一个引起变化的原因

类的每个责任都有改变的潜在区域,超过一个责任,意味着超过一个改变的区域。

组合模式

组合模式 允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

组合模式利用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,客户能把相同的操作应用在组合和个别对象上。

组合模式类图:

Component:组合中所有对象的接口。包含增加节点,删除节点,获取节点值等操作。
leaf:叶子节点实现父节点支持的操作,定义了组合内元素的行为。
Composite:普通节点定义组件的行为,连接了若干个子节点。

//组合元素接口
abstract class Component{
public:
    //所有元素的共同行为
    void commonOperation();
    //不同元素不同执行的行为
    virtual void changeOperation()=0;
    //增加节点
    virtual void add(Component element);
    //删除节点
    virtual void remove(Component element);
    //获取节点值
    virtual Object getChild(int position);
};
//普通节点
class Composite:public Component{
public:
    //子节点的共同行为
    void subCommonOperation();
    //不同子节点不同执行的行为
    virtual void fatherOperation()=0;
    //不同元素不同执行的行为
    virtual void changeOperation();
    //增加节点
    virtual void add(Component element);
    //删除节点
    virtual void remove(Component element);
    //获取节点值
    virtual Object getChild(int position);
};
//叶子节点
class Leaf:public Composite{
public:
    //子节点自己的行为
    void leafOperation();
    //需实现的父节点的行为
    virtrual void fatherOperation();
    //不同元素不同执行的行为
    virtual void changeOperation();
};

组合模式以单一责任设计原则换取透明性。透明性是指通过让组件的接口同时包含一些管理子节点和叶节点的操作,客户就可以将组合和叶节点一视同仁。

组合模式一般与迭代器连用,增加一个组合迭代器实现树的遍历。

组合模式

状态模式 允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

对象有若干种状态,每个状态封装成状态类,每种状态下有若干不同或相同的行为,每种行为可能会导致状态转移。
状态模式将状态封装成独立的类,并将动作委托到当前状态的对象,对象的行为随着内部状态而改变。

类图:

Context:上下文类,拥有一些内部状态。包含了一个request()方法,不管什么时候,只要有人调用了这个方法,它就会被委托到状态来处理。
State:所有具体状态的共同接口,任何状态都实现这个相同的接口。
ConcreteState:具体状态处理来自Context的请求,每一个具体状态都提供了它自己对于请求的实现。故而当Context改变状态时行为也跟着改变。

//状态接口
abstract class State{
public:
    virtual void change()=0;
};
//上下文
class Context{
public:
    //定义两种状态
    State *one;
    State *two;
    //当前状态
    State *cur;
    //构造函数,默认one状态
    Context():one(new StateOne(this)),two(new StateTwo())),cur(one){}
    //状态改变方法
    void changeState(){
        cur.change();
    }
    //改变当前状态
    void setCurrent(State &nowState){
        this.cur=nowState;
    }
    //获取状态值
    State getStateOne(){
        return *one;
    }
    State getStateTwo(){
        return *two;
    }
};
//状态One类
class StateOne:public State{
public:
    //存储当前上下文
    Context curCon;
    //构造函数传入上下文对象
    StateOne(Context &con):curCon(con){}
    //状态改变方法
    void change(){
        curCon.setCurrent(curCon.getStateTwo());
    }
};

状态模式将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个。随着时间的流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,但context的客户对于状态对象了解不多。但注意状态是用在context中来代表它的内部状态以及行为的,所有只有context才会对状态提出请求,客户不会直接改变context的状态。

我们可以把状态模式想象成是不用再context中放置许多条件判断的替代方案,通过将行为包装进状态对象中,你可以通过在context内简单的改变状态对象来改变context的行为。

代理模式

代理模式 为另一个对象提供一个替身或占位符以控制对这个对象的访问。

使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。

类图:

Subject:为真实对象和代理提供统一接口。
RealSubject:真正做事的对象,它是被proxy代理和控制访问的对象。
Proxy:代理持有真实对象的引用。客户和真实对象交互必须都通过代理。

MVC

MVC:Model+View+Controller
视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。
控制器:取得用户的输入并解读其对模型的意思。
模型:模型持有所有的数据、状态和程序逻辑。模型提供了操纵和检索状态的接口,并发送状态改变通知给观察者。

MVC运行过程:

  1. 用户和视图交互

    视图通知控制器用户的行为,控制器负责处理。

  2. 控制器要求模型改变状态

    控制器解读用户的动作,并告知模型做出对应的动作。

  3. 控制器也可能要求视图做改变

    控制器可能也需要告诉视图改变结果,如使界面上的某些按钮无效。

  4. 当模型状态改变时,模型会通知视图

    只要模型内的东西改变时,模型都会通知视图它的状态改变了。

  5. 视图向模型询问状态

    视图直接从模型取得它显示的状态,当控制器请求视图改变时,视图也可能向模型询问某些状态。

控制器把控制逻辑从视图中分离,让模型和视图之间解耦。

MVC中用到的设计模式:

  • 模型利用“观察者”让控制器和视图可以随最新的状态改变而更新。同一个模型可以使用不同的视图,甚至可以同时使用多个视图。
  • 视图和控制器实现了“策略模型”。控制器是视图的行为,如果客户希望有不同的行为,可以直接换一个控制器。视图是一个对象,可以被调整使用不同的策略,而控制器提供了策略。视图只关心系统中可视的部分,对于任何界面行为,都委托给控制器处理。
  • 视图内部使用“组合模式”来管理窗口、按钮以及其它显示组件。当控制器告诉视图更新时,只需告诉视图最顶层的组件即可,组合会处理其余的事。

总结


模式 是在某情景下,针对某问题的某种解决方案。

不同模式间的区别:
1.
装饰者 包装另一个对象,并提供额外的行为
外观 包装许多对象以简化它们的接口
代理 包装另一个对象,并控制对它的访问
适配器 包装另一个对象,并提供不同的接口

2.
状态 封装基于状态的行为,并将行为委托到当前状态
策略 将可以互换的行为封装起来,然后使用委托的方法,决定使用哪一个行为
模版方法 由子类决定如何实现算法中的某些步骤

3.
策略 封装可以互换的行为,并使用委托决定使用哪一个
适配器 改变一个或多个类的接口
迭代器 提供一个方式来遍历集合,而无须暴露集合的实现
外观 简化一群类的接口
组合 客户可以将对象的集合以及个别的对象一视同仁
观察者 当某个状态改变时,允许一群对象能被通知到

4.
模版方法 子类决定如何实现算法中的某些步骤
策略 封装可互换的行为,然后使用委托来决定要采用哪一个行为
工厂方法 有子类决定实例化哪个具体类

5.
装饰者 不改变接口,但加入责任
适配器 将一个接口转成另一个接口
外观 让接口更简单

猜你喜欢

转载自blog.csdn.net/sinat_30477313/article/details/80010291
今日推荐