愿你如阳光,明媚不忧伤。
目録
10. 迭代器模式
Iterator 提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。Java中的Iterator对象就是根据迭代器模式设计的。
迭代器模式优点和缺点
- 优点
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 遍历任务交由迭代器完成,这简化了聚合类。
- 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
- 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
- 封装性良好,为遍历不同的聚合结构提供一个统一的接口。
- 缺点
- 增加了类的个数,这在一定程度上增加了系统的复杂性。
迭代器模式的应用场景
- 当需要为聚合对象提供多种遍历方式时。
- 当需要为遍历不同的聚合结构提供一个统一的接口时。
- 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。
迭代器模式模式的结构
迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。1. 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
2. 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
3. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
4. 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
迭代器模式的实现
package com.example.demo.controller;
import java.util.ArrayList;
import java.util.List;
public class IteratorController {
public static void main(String[] args) {
Aggregate aggregate = new ConcreteAggregate();
aggregate.add("info1");
aggregate.add("info2");
aggregate.add("info3");
System.out.print("聚合的内容有:");
Iterator it = aggregate.getIterator();
while (it.hasNext()) {
Object obj = it.next();
System.out.print(obj.toString() + "\t");
}
Object obj = it.first();
System.out.println("\nFirst:" + obj.toString());
}
}
// 抽象聚合
interface Aggregate {
void add(Object obj);
void remove(Object obj);
Iterator getIterator();
}
// 具体聚合
class ConcreteAggregate implements Aggregate {
private final List<Object> list = new ArrayList<>();
public void add(Object obj) {
list.add(obj);
}
public void remove(Object obj) {
list.remove(obj);
}
public Iterator getIterator() {
return new ConcreteIterator(list);
}
}
// 抽象迭代器
interface Iterator {
Object first();
Object next();
boolean hasNext();
}
// 具体迭代器
class ConcreteIterator implements Iterator {
private final List<Object> list;
private int index = -1;
public ConcreteIterator(List<Object> list) {
this.list = list;
}
public boolean hasNext() {
return index < list.size() - 1;
}
public Object first() {
index = 0;
return list.get(index);
}
public Object next() {
Object obj = null;
if (this.hasNext()) {
obj = list.get(++index);
}
return obj;
}
}
-----------------------------------------------------------------
・【运行结果】
聚合的内容有:info1 info2 info3
First:info1
11. 访问者模式
Visitor 将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,例如,公园中存在多个景点,也存在多个游客,不同的游客对同一个景点的评价可能不同。是行为类模式中最复杂的一种模式。
访问者模式优点和缺点
- 优点
- 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
- 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
- 缺点
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
- 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
访问者模式的应用场景
- 对象结构相对稳定,但其操作算法经常变化的程序。
- 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。
- 对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。
访问者模式模式的结构
访问者模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类。1. 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
3. 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
4. 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
5. 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
访问者模式的实现
package com.example.demo.controller;
import java.util.ArrayList;
import java.util.List;
public class VisitorController {
public static void main(String[] args) {
ObjectStructure os = new ObjectStructure();
os.add(new ConcreteElementA());
os.add(new ConcreteElementB());
Visitor visitor = new ConcreteVisitorA();
os.accept(visitor);
System.out.println("------------------------");
visitor = new ConcreteVisitorB();
os.accept(visitor);
}
}
// 抽象访问者
interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// 具体访问者A类
class ConcreteVisitorA implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("具体访问者A访问-->" + element.operationA());
}
public void visit(ConcreteElementB element) {
System.out.println("具体访问者A访问-->" + element.operationB());
}
}
// 具体访问者B类
class ConcreteVisitorB implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("具体访问者B访问-->" + element.operationA());
}
public void visit(ConcreteElementB element) {
System.out.println("具体访问者B访问-->" + element.operationB());
}
}
// 抽象元素类
interface Element {
void accept(Visitor visitor);
}
// 具体元素A类
class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA() {
return "具体元素A的操作。";
}
}
// 具体元素B类
class ConcreteElementB implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB() {
return "具体元素B的操作。";
}
}
// 对象结构角色
class ObjectStructure {
private final List<Element> list = new ArrayList<>();
public void accept(Visitor visitor) {
for (Element element : list) {
element.accept(visitor);
}
}
public void add(Element element) {
list.add(element);
}
public void remove(Element element) {
list.remove(element);
}
}
-----------------------------------------------------------------
・【运行结果】
具体访问者A访问-->具体元素A的操作。
具体访问者A访问-->具体元素B的操作。
------------------------
具体访问者B访问-->具体元素A的操作。
具体访问者B访问-->具体元素B的操作。
访问者模式的应用实例
艺术公司利用“铜”可以设计出铜像,利用“纸”可以画出图画;造币公司利用“铜”可以印出铜币,利用“纸”可以印出纸币,对“铜”和“纸”这两种元素,两个公司的处理方法不同,所以该实例用访问者模式来实现比较适合。
package com.example.demo.controller;
import java.util.ArrayList;
import java.util.List;
public class VisitorDemoController {
public static void main(String[] args) {
MaterialSet materialSet = new MaterialSet();
materialSet.add(new Paper());
materialSet.add(new Cuprum());
System.out.println(materialSet.accept(new ArtCompany()));
System.out.println("------------------");
System.out.println(materialSet.accept(new Mint()));
}
}
// 抽象访问者
interface CompanyVisitor {
String create(Paper element);
String create(Cuprum element);
}
// 艺术公司
class ArtCompany implements CompanyVisitor {
@Override
public String create(Paper element) {
return "制作油画";
}
@Override
public String create(Cuprum element) {
return "制作铜像";
}
}
// 造币公司
class Mint implements CompanyVisitor {
@Override
public String create(Paper element) {
return "制作纸币";
}
@Override
public String create(Cuprum element) {
return "制作铜币";
}
}
// 抽象元素
interface Material {
String accept(CompanyVisitor visitor);
}
// 纸
class Paper implements Material {
@Override
public String accept(CompanyVisitor visitor) {
System.out.println("造纸启动中...");
return visitor.create(this);
}
}
// 铜
class Cuprum implements Material {
@Override
public String accept(CompanyVisitor visitor) {
System.out.println("铜板启动中...");
return visitor.create(this);
}
}
// 材料集
class MaterialSet {
private final List<Material> list = new ArrayList<>();
public String accept(CompanyVisitor visitor) {
StringBuilder sb = new StringBuilder();
for (Material element : list) {
sb.append(element.accept(visitor));
sb.append("\n");
}
return sb + "加工完毕";
}
public void add(Material element) {
list.add(element);
}
public void remove(Material element) {
list.remove(element);
}
}
-----------------------------------------------------------------
・【运行结果】
造纸启动中...
铜板启动中...
制作油画
制作铜像
加工完毕
------------------
造纸启动中...
铜板启动中...
制作纸币
制作铜币
加工完毕