当前位置: 首页 > news >正文

图解设计模式

设计模式

predefinition

UML

UML是让系统可视化、让规格和设计文档化的表现方法,全称为Unified Modeling Language

UML中的类图用于表示类、接口、实例等之间相互的静态关系。

类与层次结构

«interface»
ParentClass
int field1
char field2
void methodA()
double methodB()
ChildClass
void methodA()
void methodB()

上图展示了ParentClass和ChildClass两个类之间的关系,空心箭头表明了两者之间的层次关系,箭头由子类指向父类,即继承。反过来说,ChildClass是ParentClass的子类。父类也成为基类或者超类,子类也成为派生类

图中的长方形表示类,内部被横线自上而下分为类名字段名方法名子类一定指向父类

接口与实现

«interface»
Printable
void print()
void newPage()
PrintClass
void print()
void newPage()

带有空心三角形的虚线箭头代表了接口与实现类的关系,箭头从实现类指向接口。

聚合

Color
Fruit
Color color
Basket
Fruit[] fruits

只要在一个类中持有另外一个类的实例,无论是一个还是多个,它们之间的关系就是聚合关系。UML中使用带有空心菱形的实线表示聚合关系。

可见性(访问控制)

something
-int privateField
#int protectedField
+int publicField
~int packageField
-void privateMethod()
#void protectedMethod()
+void publicMethod()
~void packagheMethod()

+表示public方法和字段,可以从类外部访问这些方法和字段

-表示private方法和字段,无法从类外部访问这些方法和字段

#表示protected方法和字段,能够访问这些方法和字段的只能是该类自身、该类的子类以及同一包中的类

~表示同一包中的类才能访问的方法和字段

类的关联

可以在类名前面加上黑三角表示类之间的关联关系。

Client
Target

时序图

UML的时序图用来表示程序在工作时其内部方法的调用顺序,以及事件的发生顺序。

类图中表示的是“不因时间流失而发生变化的关系”,时序图则与之相反,表示的是“随时间发生变化的东西”。

处理流与对象间的协作

:Client:Server:Deviceworkopenprintwriteclose:Client:Server:Device

client、server、device是三个实例,向下延伸的线是生命线。生命线仅存在于实例的生命周期内。黑色实线箭头代表方法的调用,虚线箭头代表返回open方法。时序图的阅读顺序是沿着生命线从上至下阅读。遇到箭头时,顺着箭头所指的方向查看对象间的协作。

Iterator模式

Iterator模式用于在数据集合中按照顺序遍历集和。

示例

creates
«interface»
Aggregate
iterator()
«interface»
Iterator
hasNext()
next()
BookShelf
books
last
getBookAt()
appendBook()
getLength()
iterator()
BookShelfIterator
bookShelf
index
hasNext()
next()
Book
name
getName()

Aggerate 接口中只声明了一个iterator方法,该方法会生成一个用于遍历集和的迭代器。

// Aggerate 接口
public interface Aggregate{public abstract Iterator iterator();
}

Iterator 接口用于遍历集合中的元素,作用相当于循环语句中的循环变量。hasNext()用于判断是否存在下一个元素,next()用于获取下一个元素。

// Iterator 接口
public interface Iterator{public abstract boolean hasNext();public abstract Object next();
}

Book类是表示书的实体类。

// Book 类
public class Book{private String name;public Book(String name){this.name = name;}public String getName(){return name;}
}

BookShelf是表示书架的实体类,实现了Aggerate接口以及其中的iterator方法。

// BookShelf 类
public class BookShelf implements Aggerate{private Book[] books;private int last = 0;public BookShelf(int maxsize){this.books = new Book[maxsize];}public Book getBookAt(int index){return books[index];}public void appendBook(Book book){this.books[last] = book;last++;}public int getLength(){return last;}public Iterator iterator(){return new BookShelfIterator(this);}
}

BookShelfIterator类用于遍历书架,需要发挥Iterator的作用,实现了Iterator接口。bookShelf字段是BookShelfIterator所要遍历的书架,index字段表示迭代器当前所指向的书的下标。

// 	BookShelfIterator 类
public class BookShelfIterator implements Iterator{private BookShelf bookshelf;private int index;public BookShelfIterator(BookShelf bookShelf){this.bookShelf = bookShelf;this.index = 0;}public boolean hasNext(){if (index < bookShelf.getLength()){return true;} else{return false;}}public Object next(){Book book = bookShelf.getBookAt(index);index++;return book;}
}

使用Main类来执行所有代码。

public class Main {public static void main(String[] args) {BookShelf bookShelf = new BookShelf(4);bookShelf.appendBook(new Book("Around the World in 80 Days"));bookShelf.appendBook(new Book("Bible"));bookShelf.appendBook(new Book("Cinderella"));bookShelf.appendBook(new Book("Daddy-Long-Legs"));Iterator it = bookShelf.iterator();while (it.hasNext()) {Book book = (Book)it.next();System.out.println(book.getName());}}
}

上述代码设计了能容纳4本书的书架,然后按照书名的英文字母顺序添加进入书架内。通过bookShelf.iterator()得到的实例it是用于遍历书架的Iterator实例。

解析

Iterator中出现的角色包括IteratorConcreteIteratorAggregateConcreteAggregate

  • Iterator

    定义按顺序逐个遍历元素的API。

  • ConcreteIterator

    实现Iterator所定义的API。

  • Aggregate

    定义创建Iterator的API。

  • ConcreteAggregate

    实现Aggregate所定义的API。

类图如下:

Creates
«interface»
Aggregate
iterator()
Iterator
hasNext()
next()
ConcreteAggregate
iterator()
ConcreteIterator
aggregate
hasNext()
next()

**引入Iterator后可以将遍历与实现分离开来。**无论实体类如何变化,只要iterator方法能正确地返回实例,即使不对核心代码(while循环)做任何修改,代码都可以正常工作。这也就是设计模式的一个重要作用:帮助编写可复用的类。

如果只是用具体类来解决问题,容易导致类之间的强耦合,这些类也难以被作为组件再次利用,为了弱化类之间的耦合,使得类更容易作为组件被再次利用,需要引入抽象类和接口。

在Java中,没有使用的对象实例会自动被删除(垃圾回收)。因此在iterator中不需要与其对应的deleteIterator方法。

Adapter模式

用于填补“现有的程序”和“所需的程序”之间差异的设计模式就是Adapter模式。Adapter模式也被称为Wrapper模式。

Adapter有以下两种:

  • 类适配器模式(使用继承的适配器)
  • 对象适配器模式(使用委托的适配器)

示例

Uses
Main
«interface»
Print
printWeak()
printStrong()
PrintBanner
printWeak()
printStrong()
Banner
showWithParen()
showWithAster()

扮演适配器角色的是PrintBanner,该类继承了Banner并实现了需求——Print接口。

Banner类是当前已有的类

// Banner 类
public class Banner{private String string;public Banner(String string){this.string = string;}public void showWithParen(){System.out.println("(" + string + ")");}public void showWithAster(){System.out.println("*" + string + "*");}
}

Print接口时需求的接口

// Print 接口
public interface Print{public abstract void printWeak();public abstract void printStrong();
}

PrintBanner类扮演适配器的角色,继承了Banner类,实现了Print接口。

// PrintBanner 类
public class PrintBanner extends Banner implements Print{public PrintBanner(String string){super(string);}public void printWeak(){showWithParen();}public void printStrong(){showWithAster();}
}

Main类通过适配器PrintBanner类来进行任务执行

public class Main{public static void main(String[] args){Print p = new PrintBanner("Hello");p.printWeak();p.printStrong();}
}

类适配器的优点:直接通过继承现有类和实现目标接口来完成适配,代码简洁。缺点:由于Java不支持多重继承,如果现有类不是接口,则无法同时继承另一个类来扩展功能。同时与现有类之间存在强耦合,如果现有类发生更改,适配器也要做相应的更改。

Uses
Main
Print
printWeak()
printStrong()
PrintBanner
banner
printWeak()
printStrong()
Banner
showWithParen()
showWithAster()

Java中,委托指将某个方法中的实际处理交给其他实例的方法。

Main类和Banner与上面的代码相同,我们假设Print不是接口而是类。利用Banner类实现一个类,该类的方法和Print类的方法相同。

// Print 接口
public abstract class Print{public abstract void printWeak();public abstract void printStrong();
}
// PrinBanner 类
public class PrintBanner extends Print{private Banner banner;public PrintBanner(String string){this.banner = new Banner(string);}public void printWeak(){banner.showWithParen();}public void printStrong(){banner.showWithAster();}
}

解析

Adapter模式中有以下角色:

  • Target

    定义所需的方法

  • Client

    使用Target角色所定义的方法进行具体处理

  • Adaptee

    持有既定方法的角色

  • Adapter

    使用Adaptee角色的方法来满足Target角色的需求,这是Adapter模式的目的,也是Adapter角色的作用。

类图如下:

继承:

Uses
implements
extends
Client
«interface»
Target
targetMethod1()
targetMethod2()
Adapter
targetMethod1()
targetMethod2()
Adaptee
methodA()
methodB()
methodC()

使用委托

Uses
extends
has
Client
«interface»
Target
targetMethod1()
targetMethod2()
Adapter
adaptee
targetMethod1()
targetMethod2()
Adaptee
methodA()
methodB()
methodC()

什么时候使用Adapter模式:

Adapter模式会对现有的类进行适配,生成新的类。通过该模式可以很方便地创建我们需要的方法群。当出现bug时,由于我们很明确地知道bug不在现有的类(adaptee)中,所以只需要调查Adapter的类即可。

使用Adapter模式可以在完全不修改现有代码的前提下使现有代码适配于新的接口。在Adapter模式中也并非一定需要现成的代码,只要知道现有类的功能,就可以编写出新的类。

----------------------------------------------------------未完待续------------------------------------------------------

Reference

图解设计模式 【日】结成浩 著 杨文轩 译

http://www.dtcms.com/a/363089.html

相关文章:

  • AbMole小课堂丨Trastuzumab:靶向 HER2 的多维作用机制及科研应用详解
  • 移动端富文本markdown中表格滚动与页面滚动的冲突处理:Touch 事件 + 鼠标滚轮精确控制方案
  • 亚信安全亮相鸿蒙生态大会2025 携手鸿蒙生态绘就万物智联新蓝图
  • 技术架构设计--资源与链接、安全灾备
  • 铝基板自动矫平机·再探:从“辊缝”到“微观”的幕后故事
  • SwinIR:基于 Swin Transformer 的图像复原新范式(附视频讲解)
  • 【C++】14. 多态
  • C++ 面试考点 类成员函数的调用时机
  • 服务器的监控和管理手段有哪些?
  • Zephyr如何注册设备实例
  • Android14 init.rc各个阶段的主要操作详解2
  • 【Qt】bug排查笔记——QMetaObject::invokeMethod: No such method
  • 面试_Mysql
  • AdaBoost(Adaptive Boosting,自适应提升算法)总结梳理
  • 04 创建Centos 7操作系统
  • 基于ZooKeeper实现分布式锁(Spring Boot接入)及与Kafka实现的对比分析
  • 【Vue2 ✨】 Vue2 入门之旅(六):指令与过滤器
  • React 中 key 的作用
  • Rust SQLx 开发指南:利用 Tokio 进行性能优化
  • Spring Security资源服务器在高并发场景下的认证性能优化实践指南
  • FPGA AD7606串行驱动与并行驱动
  • AI如何理解PDF中的表格和图片?
  • 【HarmonyOS 6】仿AI唤起屏幕边缘流光特效
  • 使用Java获取本地PDF文件并解析数据
  • Echarts自定义横向柱状图中单条bar的样式
  • 从模态融合到高效检索:微算法科技 (NASDAQ:MLGO)CSS场景下的图卷积哈希方法全解析
  • 九月科技瞭望:中国科技发展规划动态洞察
  • DevExpress WPF中文教程:如何将WPF数据网格绑定到本地数据库?
  • Python 2025:量子计算、区块链与边缘计算的新前沿
  • [Linux]学习笔记系列 -- mm/swap.c 交换机制(Swap Mechanism) 物理内存的虚拟扩展