设计模式08-行为型模式1(命令模式/迭代器模式/观察者模式/Java)

五、行为型模式

  • **行为模式的定义:**行为型模式是对不同的对象之间划分职责和算法的抽象化。行为型模式定义了系统中对象之间的交互与通信,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责,包括对系统中较为复杂的流程的控制。

  • 行为模式的分类:

    类行为型模式:使用继承关系在几个类之间分配行为,主要通过多态等方式来分配父类与子类的职责;

    对象行为型模式:使用对象的聚合关联关系来分配行为,主要通过对象关联等方式来分配两个或多个类的职责。

5.1 命令模式

5.1.1 命令模式的定义

描述对象之间的调用关系

**1.模式动机:**将请求发送者和接收者完全解耦;发送者与接收者之间没有直接引用关系;发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求

**2.模式定义:**将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

5.1.2 命令模式的结构与分析

image-20241031200821297

//调用者
public class Invoker {
    private AbstractCommand ac;
    public Invoker(AbstractCommand ac) {
        this.ac = ac;
    }
    public void send() {
        ac.execute();
    }
}
//接收者
public class Receiver {
    public void action() {
    }
}
//抽象命令类
public abstract class AbstractCommand {
    public abstract void execute();
}
//具体命令类
public class ConcreteCommand extends AbstractCommand {
    private Receiver receiver = new Receiver();
    @Override
    public void execute() {
        receiver.action();
    }
}
  • 命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分开

  • 将请求发送者和接收者完全解耦,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

5.1.3 命令模式的案例

电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。显然,电视机遥控器就是一个典型的命令模式应用实例。

image-20241031203956626

public class TV {
    public void open() {
        System.out.println("打开电视");
    }

    public void change() {
        System.out.println("切换频道");
    }

    public void close() {
        System.out.println("关掉电视");
    }
}

public interface Command {
    public void execute();
}

public class OpenCommand implements Command{
    private TV tv = new TV();

    @Override
    public void execute() {
        tv.open();
    }
}

public class CloseCommand implements Command{
    private TV tv = new TV();
    @Override
    public void execute() {
        tv.close();
    }
}

public class ChangeCommand implements Command {
    private TV tv = new TV();
    @Override
    public void execute() {
        tv.change();
    }
}

public class Control {
    private Command openCommand;
    private Command changeCommand;
    private Command closeCommand;

    public Control(Command openCommand, Command changeCommand, Command closeCommand) {
        this.openCommand = openCommand;
        this.changeCommand = changeCommand;
        this.closeCommand = closeCommand;
    }

    public void open() {
        openCommand.execute();
    }

    public void change() {
        changeCommand.execute();
    }

    public void close() {
        closeCommand.execute();
    }
}

public class Main {
    public static void main(String[] args) {
        Command openCommand = new OpenCommand();
        Command changeCommandCommand = new ChangeCommand();
        Command closeCommand = new CloseCommand();
        Control control = new Control(openCommand, changeCommandCommand, closeCommand);
        control.open();
        control.change();
        control.close();
    }
}
5.1.4 命令模式的优缺点
优点 缺点
1.将系统的请求调用者和请求接收者解耦 1.使用命令模式可能会导致某些系统有过多的具体命令类
2.添加命令符合开闭原则
3.可以比较容易地设计一个命令队列或宏命令(组合模式)
4.为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案
5.1.5 命令模式的适用场景
  • 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互

  • 需要在不同的时间指定请求、将请求排队和执行请求

  • 需要支持命令的撤销(Undo)操作和恢复(Redo)操作

  • 需要将一组操作组合在一起形成宏命令

5.2 迭代器模式

5.2.1 迭代器模式的定义

1.模式动机:如何访问一个聚合对象(用于存储多个对象)中的元素但又不需要暴露它的内部结构,还能提供多种不同的遍历方式

2.模式定义:提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示。

5.2.2 迭代器模式的结构与分析

image-20241102214037189

  • 聚合对象的两个职责:存储数据,聚合对象的基本职责;遍历数据,既是可变化的,又是可分离的

  • 将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中,由迭代器来提供遍历聚合对象内部数据的行为,简化聚合对象的设计,更符合单一职责原则

  • 迭代器对象使用了工厂模式的设计思想,聚合类可以看作工厂模式,迭代器是产品类

实现方法一:由于集合和数组在聚合类中,迭代器需要使用它们,因此迭代器作为内部类出现

public interface Iterator {
    public void first();
    public void next();
    public boolean isLast();
    public Object currentItem();
}

public abstract class Aggregate {
    public abstract Iterator createIterator();
}

public class ConcreteAggregate extends Aggregate{
    private String[] strings;
    public ConcreteAggregate() {
        strings = new String[]{"d", "e", "f"};
    }
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator();
    }

    private class ConcreteIterator implements Iterator{
        private int index = 0;

        @Override
        public void first() {
            index = 0;
        }

        @Override
        public void next() {
            if (strings.length > index) {
                index++;
            } else {
                throw new RuntimeException("越界");
            }
        }

        @Override
        public boolean isLast() {
            return index == strings.length;
        }

        @Override
        public Object currentItem() {
            return strings[index];
        }
    }
}

实现方法二:可以在聚合类创建迭代器时,将自身传给迭代器并提供集合/数组的get方法,这样也可以实现

public interface Iterator {
    public void first();
    public void next();
    public boolean isLast();
    public Object currentItem();
}

public abstract class Aggregate {
    public abstract Iterator createIterator();
}

public class ConcreteAggregate extends Aggregate{
    private String[] strings;
    public ConcreteAggregate() {
        strings = new String[]{"a", "b", "c"};
    }

    public String[] getStrings() {
        return strings;
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(this);
    }
}

public class ConcreteIterator implements Iterator{
    private ConcreteAggregate aggregate;
    private int index = 0;
    public ConcreteIterator(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
    }
    @Override
    public void first() {
        index = 0;
    }

    @Override
    public void next() {
        if (aggregate.getStrings().length > index) {
            index++;
        } else {
            throw new RuntimeException("越界");
        }
    }

    @Override
    public boolean isLast() {
        return index == aggregate.getStrings().length;
    }

    @Override
    public Object currentItem() {
        return aggregate.getStrings()[index];
    }
}

public class Main {
    public static void main(String[] args) {
        Aggregate concreteAggregate = new ConcreteAggregate();
        Iterator iterator = concreteAggregate.createIterator();
        while (!iterator.isLast()) {
            System.out.println(iterator.currentItem());
            iterator.next();
        }
    }
}
5.2.3 迭代器模式的案例

电视机遥控器就是一个迭代器的实例,通过它可以实现对电视机频道集合的遍历操作,本实例我们将模拟电视机遥控器的实现。

image-20241102215617007

  • 迭代器类
public interface TVIterator {
    public void setChannel(int i);
    public Object currentChannel();
    public void next();
    public void previous();
    public boolean isLast();
    public boolean isFirst();
}

public class SkyworthIterator implements TVIterator {
    private SkyworthTelevision skyworthTelevision;
    private int index = 0;

    public SkyworthIterator(SkyworthTelevision skyworthTelevision) {
        this.skyworthTelevision = skyworthTelevision;
    }

    @Override
    public void setChannel(int i) {
        this.index = i;
    }

    @Override
    public Object currentChannel() {
        return skyworthTelevision.getObj()[this.index];
    }

    @Override
    public void next() {
        if (this.index < skyworthTelevision.getObj().length) {
            this.index++;
        }
    }

    @Override
    public void previous() {
        if (this.index > 0) {
            this.index--;
        }
    }

    @Override
    public boolean isLast() {
        return this.index == skyworthTelevision.getObj().length ;
    }

    @Override
    public boolean isFirst() {
        return this.index == 0;
    }
}

public class TCLIterator implements TVIterator{
    private TCLTelevision tclTelevision;
    private int index = 0;

    public TCLIterator(TCLTelevision tclTelevision) {
        this.tclTelevision = tclTelevision;
    }

    @Override
    public void setChannel(int i) {
        this.index = i;
    }

    @Override
    public Object currentChannel() {
        return tclTelevision.getObj()[this.index];
    }

    @Override
    public void next() {
        if (this.index < tclTelevision.getObj().length) {
            this.index++;
        }
    }

    @Override
    public void previous() {
        if (this.index > 0) {
            this.index--;
        }
    }

    @Override
    public boolean isLast() {
        return this.index == tclTelevision.getObj().length;
    }

    @Override
    public boolean isFirst() {
        return this.index == 0;
    }
}
  • 电视类
public interface Television {
    public TVIterator createIterator();

    public Object[] getObj();
}

public class SkyworthTelevision implements Television{
    private Object[] obj = {"CCTV-1","CCTV-2","CCTV-3","CCTV-4","CCTV-5","CCTV-6","CCTV-7","CCTV-8"};
    @Override
    public TVIterator createIterator() {
        return new SkyworthIterator(this);
    }

    @Override
    public Object[] getObj() {
        return obj;
    }
}

public class TCLTelevision implements Television{
    private Object[] obj = {"CCTV-1","CCTV-2","CCTV-3","CCTV-4","CCTV-5","CCTV-6","CCTV-7","CCTV-8"};
    @Override
    public TVIterator createIterator() {
        return new TCLIterator(this);
    }

    @Override
    public Object[] getObj() {
        return obj;
    }
}
  • 客户端
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class XMLUtil {
    public static Object getBean() {
        try {
            //获取XML
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document parse = db.parse(new File("src/main/java/com/tyut/text3/example1/tv.xml"));
            String tv = parse.getElementsByTagName("tv").item(0).getFirstChild().getNodeValue();

            //获取对象
            Class<?> aClass = Class.forName(tv);
            
上一篇:头歌答案-分布式文件系统HDFS


下一篇:移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (6) - 触屏事件