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

图解设计模式

设计模式

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.xdnf.cn/news/19782.html

相关文章:

  • python - ( js )object对象、json对象、字符串对象的相关方法、数组对象的相关方法、BOM对象、BOM模型中 Navigator 对象
  • Ubuntu中配置JMmeter工具
  • Java 类加载机制(ClassLoader)的必会知识点汇总
  • 当合规成为主旋律,PSP 如何推动链上消费市场迈向新蓝海?
  • MidJourney AI绘图工具测评:支持Discord指令生成图片,含图生图与非商业版权使用功能
  • 零样本视觉模型(DINOv3)
  • 云手机发展:未来的场景变化
  • 【C++】模板(初阶)--- 初步认识模板
  • 三维重建线结构光之重建原理(单线结构光为例)
  • 避坑指南!解决Navicat运行SQL成功但没有表的问题
  • 达梦数据库在大小写不敏感的情况下,如何使查询比较中依旧可以做大小写敏感比较?
  • FFmpeg命令行音视频工具:高效实现格式转换与批量处理,支持音频提取与精准视频剪辑
  • Parasoft C/C++test如何实现开发环境内嵌的安全检测
  • 多工况切换定向:陀螺定向短节 vs 传统陀螺工具,谁的适配性更强?
  • 【单片机day01】
  • 学习React-8-useImmer
  • TDK InvenSense CH201距离传感器
  • 还在从零开发AI应用?这个项目直接给你500个现成方案!!!
  • Autosar之Det模块
  • 智慧工地如何撕掉“高危低效”标签?三大社会效益重构建筑业价值坐标
  • 贝叶斯定理
  • WAF与CDN在网络安全中的协同作用
  • GitLens VS Code插件测评:助力代码协作高效查提交记录,轻松解决分支管理与代码冲突
  • `<meter> ` 元素 无需 JavaScript/CSS 实现密码强度提示
  • esp32小智ai对话机器人
  • 【字节拥抱开源】 UXO 团队开源 USO: 通过解耦与奖励学习实现的统一风格与主题驱动生成
  • 万和电气卢宇聪:在“慢周期”做本质的事
  • GoLand IDE 无法识别 Go 工作区中的引用,如何解决?
  • 5.kafka集群安装
  • 区间DP .