设计模式学习(1)适应设计模式
作者:互联网
迭代器模式
-
Iterator 迭代器接口
public interface Iterator{ boolean hasNext(); // 是否有下一个元素 Object next(); // 返回下一个元素 }
-
Aggregate 集合接口
// 集合接口 public interface Aggregate{ Iterator iterator(); }
例子
Iterator有个问题是:
- 迭代器的next如何实现?保存集合的引用以及相关的信息,后面的例子会看到
- 集合需要保存迭代器的引用吗? 不用,每次调用iterator获取迭代器的时候直接new一个就可以了
下面我们用迭代器模式来实现遍历书架上的书
class Book {
private String name;
public Book(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
class BookShelf implements Aggregate {
private Book[] books;
private int bookNumber;
public BookShelf(int capacity) {
books = new Book[capacity];
bookNumber = 0;
}
public Book getBook(int index) {
return books[index];
}
public void addBook(Book book) {
books[bookNumber++] = book;
}
public int length() {
return bookNumber;
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
BookShelfIterator(BookShelf shelf) {
bookShelf = shelf;
index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.length();
}
@Override
public Object next() {
return bookShelf.getBook(index++);
}
}
// main函数
public class IteratorTest {
public static void main(String[] args) {
Book book1 = new Book("English");
Book book2 = new Book("Math");
Book book3 = new Book("Chinese");
BookShelf bookShelf = new BookShelf(10);
bookShelf.addBook(book1);
bookShelf.addBook(book2);
bookShelf.addBook(book3);
Iterator bookIterator = bookShelf.iterator();
while (bookIterator.hasNext()) {
System.out.println(bookIterator.next());
}
}
}
角色
- Iterator 迭代器接口
- Aggregate 集合接口
- 具体的Iterator,上例是BookShelfIterator
- 具体的Aggregate,上例是BookShelf
注意
- 引入迭代器后,可以将遍历单独分离开,因为遍历方式可能会有很多种,for循环遍历是最基础的一种。
- Iterator会保存Aggregate的引用,所以它知道怎么在Aggregate中获取元素。那么当Aggregate获取元素的方法改变后,Iterator也要变
- next不是返回下一个元素,而是返回当前,并指向下一个
- 当next指向的元素超过了集合范围,hasNext就应该返回false
- 迭代器可以next遍历,也可以previous遍历,有的还能跳跃式遍历
相关设计模式
- 访问者模式Visitor
- 组合模式Composite
- 工厂方法Factory Method
适配器模式
我们现在想要实现printWeak和printStrong两个打印方法。这两个方法已经在Banner中实现了,但是接口不同。在Banner中实现的名字叫showWithParen和showWithAster。
现在我们想通过一个适配器,把这俩接口名改过来
// 横幅类
// 提供了两种显示的方法
// 但是这两个接口与我们希望的不符合
class Banner{
private String string; // 横幅的内容
public Banner(String str) {
string = str;
}
// 圆括号显示
public void showWithParen(){
System.out.println("(" + string + ")");
}
// 星号显示
public void showWithAster(){
System.out.println("*" + string + "*");
}
}
interface Print{
void printWeak();
void printStrong();
}
class PrintBanner extends Banner implements Print{
public PrintBanner(String str) {
super(str);
}
@Override
public void printWeak() {
showWithParen();
}
@Override
public void printStrong() {
showWithAster();
}
}
public class AdaptorTest {
public static void main(String[] args) {
PrintBanner printBanner = new PrintBanner("ahahaha");
printBanner.printWeak();
printBanner.printStrong();
}
}
上面这种实现方式是通过继承原类,并实现接口。下面还有一种是通过委托的方法
abstract class Print{
public abstract void printWeak();
public abstract void printStrong();
}
class PrintBanner extends Print{
Banner banner;
public PrintBanner(String str) {
banner = new Banner(str);
}
@Override
public void printWeak() {
banner.showWithParen();
}
@Override
public void printStrong() {
banner.showWithAster();
}
}
角色
继承版本的
委托版本的,与继承不同的地方是
- Adapter不再是接口,而是抽象类
- Adapter拥有了一个原类的对象
注意
- 使用适配器是为了不修改源码,当我们需要使用某个库,但是又不是很喜欢它的接口,可以用适配器做一个包装。
- 适配器的好处是,源库没有动,只需要测试适配器即可。只要源码动了,不管是改了什么,都需要做测试
- 版本升级的时候,为了与旧版本兼容,可以在新版本上写一个适配器来适配旧版本。
相关设计模式
桥接模式:将功能与实现分离
装饰器模式:在不改变接口的情况下,增加新的功能
标签:学习,String,Iterator,void,适应,Book,bookShelf,设计模式,public 来源: https://www.cnblogs.com/destinyzk/p/16583120.html