行为模式

策略(Strategy)模式

  • 定义:
    • 针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得他们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。可插入式(Pluggable)的算法
        
  • 结构:

  

  • 组成:
    • 环境(Context)角色:表示策略的使用环境,它持有一个 Strategy 对象的引用
    • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口
    • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为
        
  • 什么时候用
    • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么策略模式可以动态地让一个对象在许多行为中选择一种行为
    • 一个系统需要动态地在几种算法中选择一种
    • 一个系统的算法使用的数据不可以让客户端知道
        
  • 优点:
    • 可以动态的改变对象行为
    • 是 “开-闭” 原则的一个极好的应用范例
        
  • 缺点
    • 客户必须知道所有策略类
    • 可能产生很多策略类
        
  • 策略模式与桥梁模式的异同
    • 策略模式与很多其它的模式都有着广泛的联系。Strategy 很容易和 Bridge 模式相混淆。虽然它们结构很相似,但它们却是为解决不同的问题而设计的。Strategy 模式注重于算法的封装,而 Bridge 模式注重于分离抽象和实现,为一个抽象体系提供不同的实现。Bridge 模式与 Strategy 模式都很好的体现了"复合优先于继承"的观点
        
  • 策略模式与状态模式的异同
    • 策略模式客户端可以完全控制所使用的策略,而状态模式是根据对象的不同状态执行不同策略
        
  • 例子:
        package code;
    
        abstract class Discount{
            abstract double calculate_Discount();
        }
    
        class No_Discount extends Discount
        {
            private double price = 0.0;
            private int cnt = 0;
    
            public No_Discount(double p, int c)
            {
                this.price = p;
                this.cnt = c;
            }
    
            public double calculate_Discount()
            {
                return 0.0;
            }
        }
    
        class FlatRate extends Discount
        {
            private double amount;
            private double price = 0;
            private int cnt = 0;
    
            public FlatRate(double price, int cnt, double amount)
            {
                this.price = price;
                this.cnt = cnt;
                this.amount = amount;
            }
    
            public double getAmount()
            {
                return amount;
            }
    
            public double calculate_Discount()
            {
                return cnt * amount;
            }
        }
    
        class Percentage extends Discount
        {
            private double percent = 0.0;
            private double price = 0.0;
            private int cnt = 0;
    
            public Percentage(double price, int cnt, double percent)
            {
                this.price = price;
                this.cnt = cnt;
                this.percent = percent;
            }
    
            public double getPercent()
            {
                return percent;
            }
    
            public double calculate_Discount()
            {
                return cnt * price * percent;
            }
    
        }
    
        class test {
            public static void main(String[] args) {
                double price = 20;
                int copies = 2;
                Discount plan1 = new No_Discount(price, copies);
                System.out.println(plan1.calculate_Discount());
    
                Discount plan2 = new FlatRate(price, copies, 0.8);
                System.out.println(plan2.calculate_Discount());
    
                Discount plan3 = new Percentage(price, copies, 0.3);
                System.out.println(plan3.calculate_Discount());
            }
        }
    

  

模版方法(Template Method)模式

  • 定义:
    • 模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现,仅仅使用继承机制
        
  • 结构:

  

  • 组成:
    • 抽象类:定义算法骨架
    • 具体类:实现抽象类中的抽象方法
        
  • 优点:
    • 封装不变部分,扩展可变部分
    • 行为由父类控制,子类实现
        
  • 缺点
    • 算法骨架需要改变时需要修改抽象类
        
  • 例子:
        package code;
    
        abstract class AbstractPerson{
            //抽象类定义整个流程骨架
            public void prepareGotoSchool(){
                dressUp();
                eatBreakfast();
                takeThings();
            }
            //以下是不同子类根据自身特性完成的具体步骤
            protected abstract void dressUp();
            protected abstract void eatBreakfast();
            protected abstract void takeThings();
        }
    
        class Student extends AbstractPerson{
            @Override
            protected void dressUp() {
                System.out.println("穿校服");
            }
            @Override
            protected void eatBreakfast() {
                System.out.println("吃妈妈做好的早饭");
            }
    
            @Override
            protected void takeThings() {
                System.out.println("背书包,带上家庭作业和红领巾");
            }
        }
    
        class Teacher extends AbstractPerson{
            @Override
            protected void dressUp() {
                System.out.println("穿工作服");
            }
            @Override
            protected void eatBreakfast() {
                System.out.println("做早饭,照顾孩子吃早饭");
            }
    
            @Override
            protected void takeThings() {
                System.out.println("带上昨晚准备的考卷");
            }
        }
    
        class test {
            public static void main(String[] args) {
                Student student = new Student();
                student.prepareGotoSchool();
            
                Teacher teacher  = new Teacher();
                teacher.prepareGotoSchool();
            }
        }
    

  

观察者模式(Observer)

  • 定义:

    • 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己
        
  • 结构:

  

  • 组成:
    • 抽象主题(Subject)角色:主题角色把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色
    • 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口
    • 具体主题(Concrete Subject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题又叫做具体被观察者(Concrete Observable)。具体主题角色负责实现对观察者引用的聚集的管理方法
    • 具体观察者(Concrete Observer)角色:实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题 的状态相协调
        
  • 优点:
    • 观察者模式在被观察者和观察者之间建立一个抽象的耦合
    • 观察者模式支持广播通信
        
  • 缺点
    • 如果一个被观察者有很多的观察者,将所有的观察者都通知到会花费很多时间
    • 如果在被观察者之间有循环依赖,被观察者会触发它们之间进行循环调用,导致系统崩溃
    • 虽然观察者随时知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎样发生变化的
        
  • 例子:
    • 第一种,Subject 中只有函数声明
        package code;
        import java.util.Vector;
    
        interface Subject{
            public void add(Observer a);
            public void remove(Observer a);
            public void tongzhi();    // 通知
        }
    
        // 被观察的对象
        class son_Subject implements Subject{
            private Vector<Observer> Observers = new Vector<Observer>();
            private int state = 0;
            public void add(Observer a)
            {
                Observers.add(a);
            }
            public void remove(Observer a)
            {
                Observers.remove(a);
            }
            public void tongzhi()
            {
                for(int i = 0; i < Observers.size(); ++i)
                    Observers.get(i).update();
            }
            public void getstate()
            {
                System.out.println(state);
            }
            public void setstate(int n)
            {
                this.state = n;
                tongzhi();
            }
        }
    
        interface Observer{
            public void update();
        }
    
        class Observer1 implements Observer{
            public void update()
            {
                System.out.println("被观察者已经更新");
            }
        }
    
        class Observer2 implements Observer{
            public void update()
            {
                System.out.println("被观察者已经更新");
            }
        }
    
        class test {
            public static void main(String[] args) {
                Observer1 one = new Observer1();
                Observer2 two = new Observer2();
    
                Subject s = new son_Subject();
                s.add(one);
                s.add(two);
    
                s.getstate();
                s.tongzhi();
            }
        }
    
    • 第二种,因为函数实现都是一样的,所以把函数实现也放入接口中
        package code;
        import java.util.Vector;
    
        abstract class Subject{
            private Vector<Observer> Observers = new Vector<Observer>();
            public void add(Observer a)
            {
                Observers.add(a);
            }
            public void remove(Observer a)
            {
                Observers.remove(a);
            }
            public void tongzhi()    // 通知
            {
                for(int i = 0; i < Observers.size(); ++i)
                    Observers.get(i).update();
            }
        }
    
        // 被观察的对象
        class son_Subject extends Subject{
            private int state = 0;
    
            public void getstate()
            {
                System.out.println(state);
            }
            public void change(int n)
            {
                this.state = n;
                tongzhi();
            }
        }
    
        interface Observer{
            public void update();
        }
    
        class Observer1 implements Observer{
            public void update()
            {
                System.out.println("被观察者已经更新");
            }
        }
    
        class Observer2 implements Observer{
            public void update()
            {
                System.out.println("被观察者已经更新");
            }
        }
    
        class test {
            public static void main(String[] args) {
                Observer1 one = new Observer1();
                Observer2 two = new Observer2();
    
                son_Subject s = new son_Subject();
                s.add(one);
                s.add(two);
    
                s.getstate();
                s.change(5);
                s.getstate();
            }
        }
    

  

命令(Command)模式

  • 定义:
    • 接收者(Receiver)角色:任何一个类都可以成为接收者; 实施和执行请求的方法叫做行动方法
        
  • 结构:

  

  • 组成:
    • 客户端(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者
    • 命令角色(Command):声明了一个给所有具体命令类的抽象接口
    • 具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱偶合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法
    • 请求者(Invoker)角色:负责发出一个请求
    • 接收者(Receiver)角色:任何一个类都可以成为接收者;实施和执行请求的方法叫做行动方法
        
  • 优点:
    • 请求一个操作的对象与知道怎么执行一个操作的对象分割开
    • 可以把命令对象聚合在一起,合成为合成命令
    • 增加新的具体命令类很容易
        
  • 缺点
    • 会导致某些系统有过多的具体命令类
        
  • 例子:
        package code;
    
        interface Command{
            public void execute();
        }
    
        class PlayCommand implements Command{
            private AudioPlayer myAudio;
            PlayCommand(AudioPlayer m)
            {
                myAudio = m;
            }
            public void execute()
            {
                myAudio.play();
            }
        }
    
        class StopCommand implements Command{
            private AudioPlayer myAudio;
            StopCommand(AudioPlayer m)
            {
                myAudio = m;
            }
            public void execute()
            {
                myAudio.stop();
            }
        }
    
        class RewindCommand implements Command{
            private AudioPlayer myAudio;
            RewindCommand(AudioPlayer m)
            {
                myAudio = m;
            }
            public void execute()
            {
                myAudio.rewind();
            }
        }
    
        class Keypad{
            private Command play;
            private Command stop;
            private Command rewind;
    
            public Keypad(Command play, Command stop, Command rewind)
            {
                this.play = play;
                this.stop = stop;
                this.rewind = rewind;
            }
    
            public void play()
            {
                play.execute();
            }
    
            public void stop()
            {
                stop.execute();
            }
    
            public void rewind()
            {
                rewind.execute();
            }
        }
    
        class AudioPlayer
        {
        public void play()
        {
            System.out.println("Playing…");
        }
        public void stop()
        {
            System.out.println("Stopped.");
        }
        public void rewind()
        {
            System.out.println("Rewinding…");
        }
        }
    
        class test {
            public static void main(String[] args) {
                AudioPlayer my = new AudioPlayer();
                PlayCommand p = new PlayCommand(my);
                StopCommand s = new StopCommand(my);
                RewindCommand r = new RewindCommand(my);
                Keypad k = new Keypad(p, s, r);
    
                k.play();
                k.stop();
                k.rewind();
            }
        }
    

  

状态(State)模式

  • 定义:
    • 允许一个对象在其内部状态改变的时候改变其行为
        
  • 结构:

  

  • 组成:
    • Context: 环境类,定义客户感兴趣的接口,维护一个 State 子类的实例,这个实例对应的是对象当前的状态
    • State:抽象状态类或者状态接口,定义一个或者一组行为接口,表示该状态下的行为动作
    • ConcreteState: 具体状态类,实现 State 抽象类中定义的接口方法,从而达到不同状态下的不同行为
        
  • 优点:
    • 可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
        
  • 缺点
    • 状态较多时会产生过多对象
        
  • 例子:
        package code;
    
        class Context{
            private State state;
            public void operation()
            {
                state.operation();
            }
            public void set_state(State newstate)
            {
                this.state = newstate;
            }
        }
    
        abstract class State{
            public abstract void operation();
        }
    
        class state1 extends State{
            public void operation()
            {
                System.out.println("状态1下操作");
            }
        }
    
        class state2 extends State{
            public void operation()
            {
                System.out.println("状态2下操作");
            }
        }
    
        class test {
            public static void main(String[] args) {
                Context c = new Context();
                state1 one = new state1();
                state2 two = new state2();
    
                c.set_state(one);
                c.operation();
    
                c.set_state(two);
                c.operation();
            }
        }
    

  

中介者(Mediator)模式

  • 定义:
    • 对象之间不直接发生相互作用,它们通过中介者对象与其他对象发生相互作用
        
  • 结构:

  

  • 组成:
    • 抽象中介者角色:定义出中介者对象的接口
    • 具体中介者角色:从抽象中介者继承而来,实现了抽象超类所声明的事件方法。具体中介者知晓所有的具体同事类,它从具体同事对象接受消息、向具体同事对象发出命令
    • 抽象同事类角色:定义同事对象的接口。同事对象只知道中介者而不知道其余的同事对象
    • 具体同事类角色:所有的具体同事类均从抽象同事类继承而来
        
  • 优点:
    • 适当使用中介者模式可以避免同事对象之间的过度耦合,使得中介类与同事类可以相对对立的演化
    • 中介者模式将多对多的相互作用转化为一对多的相互作用,使得对象之间的关系更加易于维护和理解
    • 体现了迪米特法则
        
  • 缺点
    • “中介“承担了较多的责任,所以一旦这个中介对象出现了问题,那么整个系统就会受到重大的影响
        
  • 例子:
        package code;
    
        interface Mediator
        {
            void send(String message, Person person);
        }
    
        class MediatorStructure implements Mediator
        {
            // 中介者必须知道所有对象
            private HouseOwner houseOwner;
            private Tenant tenant;
    
            public void setHouseOwner(HouseOwner houseOwner)
            {
                this.houseOwner = houseOwner;
            }
    
            public void setTenant(Tenant tenant)
            {
                this.tenant = tenant;
            }
    
            @Override
            public void send(String message, Person person)
            {
                // 中介负责转发,收到房东信息就发给租客,反过来租客信息就发给房东
                if(person == houseOwner)
                    tenant.getMessage(message);
                else
                    houseOwner.getMessage(message);
            }
        }
    
        abstract class Person
        {
            protected String name;
            protected Mediator mediator;
    
            Person(String name, Mediator mediator)
            {
                this.name = name;
                this.mediator = mediator;
            }
        }
    
        class HouseOwner extends Person
        {
            HouseOwner(String name, Mediator mediator)
            {
                super(name, mediator);
            }
    
            public void sendMessage(String message)
            {
                mediator.send(message, this);
            }
    
            public void getMessage(String message)
            {
                System.out.println("HouseOwner : "+name+", Get Message: "+message);
            }
        }
    
        class Tenant extends Person
        {
            Tenant(String name, Mediator mediator)
            {
                super(name, mediator);
            }
    
            public void sendMessage(String message)
            {
                mediator.send(message, this);
            }
    
            public void getMessage(String message)
            {
                System.out.println("Tenant : "+name+", Get Message: "+message);
            }
        }
    
        class test {
            public static void main(String[] args) {
                MediatorStructure mediator = new MediatorStructure();
    
                HouseOwner houseOwner = new HouseOwner("qq", mediator);
                Tenant tenant = new Tenant("jj", mediator);
    
                mediator.setHouseOwner(houseOwner);
                mediator.setTenant(tenant);
    
                tenant.sendMessage("I wanna a house");
                houseOwner.sendMessage("I have~");
            }
        }
    

  

posted @ 2020-11-20 03:09  物转星移几度秋  阅读(106)  评论(0)    收藏  举报