本文是学习设计模式后,自己做的笔记。
学习资源有菜鸟教程以及尚硅谷韩顺平图解设计模式。
本文是设计模式——11个行为型设计模式的上半篇。
文章目录
1、模板模式
概述:
可以让一个类的行为或其算法可以在运行时更改的设计模式。
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
特点:
可以让一个类的行为或其算法可以在运行时更改的设计模式。
角色:
1、抽象对象
2、继承实现对象
类图示例:
步骤代码实现:
目标:按照步骤生产豆浆,豆浆可以由不同的材料构成。
- 豆浆抽象类,定义生产的主要顺序
//抽象类,表示豆浆
public abstract class SoyaMilk {
//模板方法, make , 模板方法可以做成 final , 不让子类去覆盖. final void make() {
select();
addCondiments();
soak();
beat();
}
//选材料
void select() {
System.out.println("第一步:选择好的新鲜黄豆 ");
}
//添加不同的配料, 抽象方法, 子类具体实现
abstract void addCondiments();
//浸泡
void soak() {
System.out.println("第三步, 黄豆和配料开始浸泡, 需要 3 小时 ");
}
void beat() {
System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
}
}
- 豆浆实现类,可以有针对性实现不同的方法
public static int Sum_Solution(int n) {
int sum = n;
boolean flag = (sum > 0) && ((sum += Sum_Solution(--n)) > 0);
return sum;
}
}
public class PeanutSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的花生 ");
}
}
public class RedBeanSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的红豆 ");
}
}
- 客户端调用
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//制作红豆豆浆
System.out.println("----制作红豆豆浆----");
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
System.out.println("----制作花生豆浆----");
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
}
}
模板方法模式的注意事项和细节
- 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
- 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
- 优点:既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步
骤的实现。 - 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 一般模板方法都加上 final 关键字, 防止子类重写模板方法.
- 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理
2、命令模式
概述:
是一种数据驱动的设计模式。
-
在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计
-
命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
-
在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
-
通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
-
Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象
特点:
请求以命令的形式包裹在对象中,并传给调用对象。
调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
接触命令发送者跟命令接受者的耦合关系,让对象间的调用更加灵活。
角色:
1、命令类接口
2、命令类实体类(内部聚合接收者类)
3、接收者类
4、命令者(聚合命令类实体)
类图示例:
这里的Controller就是将军的角色,Comand就是命令类,值得注意的是士兵角色需要继承命令类,这里就是为了在创建命令类时可以将控制命令传递过去。
步骤代码实现:
- 创建命令接口
//1、命令类接口
//创建命令接口
public interface Command {
//执行动作
public void execute();
//取消动作
public void undo();
}
- 创建命令实现类
//2、命令类实现类
public class LightOffCommand implements Command{
private LightReceiver light;
public LightOffCommand(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.off();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.on();
}
}
public class LingtOnCommad implements Command{
//这里的light可以是继承了command接口的其他对象
//内部聚合信号接收者
//这里就是实现了通过命令类传递命令
private LightReceiver light;
public LingtOnCommad(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.on();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.off();
}
}
- 创建命令接收者(士兵的角色)
//3、命令接受处理者
//独立的执行者类
public class LightReceiver {
public void on() {
System.out.println("电灯打开了!");
}
public void off() {
System.out.println("电灯关闭了!");
}
}
- 创建聚合控制器类(将军的角色)
//4、聚合控制器类,命令发布者类
//持有多个命令数组,用于调用命令
public class RemoteController {
//开始的操作
Command[] onCommands;
Command[] offCommands;
//取消的操作
Command undoCommand;
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < 5; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
//设置按钮
public void setCommand(int no ,Command oncommand,Command offcommand) {
onCommands[no] = oncommand;
offCommands[no] = offcommand;
}
public void onButtonwasPushed(int no) {
onCommands[no].execute();
//执行操作后记住本次对象
undoCommand = onCommands[no];
}
public void offButtonwasPushed(int no) {
offCommands[no].execute();
//执行操作后记住本次对象
undoCommand = offCommands[no];
}
public void undoButtonwasPushed() {
undoCommand.undo();
}
}
- 创建空对象类用于初始化
//5、空对象类用于初始化
//空实现的对象用处初始化
public class NoCommand implements Command{
public NoCommand() {
// TODO Auto-generated constructor stub
}
@Override
public void execute() {
// TODO Auto-generated method stub
}
@Override
public void undo() {
// TODO Auto-generated method stub
}
}
- 调用
//6、客户端调用
public class Client {
public static void main(String[] args) {
//利用命令模式通过遥控调用电视
//创建接收者
LightReceiver lightreceiver = new LightReceiver();
//创建开关信号
//这里就是通过命令类传递信号,在创建命令的时候将相关的接收者传送进去,实现传递命令的目的
LingtOnCommad lightoncommand = new LingtOnCommad(lightreceiver);
LightOffCommand lightoffcommand = new LightOffCommand(lightreceiver);
RemoteController remotecontroller = new RemoteController();
remotecontroller.setCommand(0, lightoncommand, lightoffcommand);
System.out.println("-------按下开的按钮!-----------");
remotecontroller.onButtonwasPushed(0);
System.out.println("-------按下关的按钮!-----------");
remotecontroller.offButtonwasPushed(0);
System.out.println("-------按下取消的按钮!-----------");
remotecontroller.undoButtonwasPushed();
}
}
命令模式的注意事项和细节
- 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
- 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
- 容易实现对请求的撤销和重做
- 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
- 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
- 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发- 反馈机制
3、访问者模式
概述
访问者模式是最复杂的一种设计模式,核心就是要理解一句话:你带着好奇心去朋友家拜访,朋友把家里的情况描述给你,你了解后针对好奇心解决疑惑。这就是设计者模式的整体流程。
一种使用了一个访问者类来改变了元素类的执行算法的设计模式。
- 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
- 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
- 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
- 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
特点:
封装一些作用与某种数据结构的各元素的操作,可以在不改变数据结构的前提下重新定义作用与这些元素的新操作。
解决数据结构跟操作耦合性问题。
在被访问的类里面加一个对外提供访问者的接口。
您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
角色:
1、抽象访问者:对数据结构进行操作
2、实体访问者
3、抽象元素类:提供一个aceept方法来接受访问者,并且在accep中返回自己的情况。
4、具体元素类
5、ObjectStructure:能枚举他的元素,提供一个高层接口,用来允许访问者访问元素
类图示例:
这里Element就是主人,Visitor就是客人。
客人来访的时候,主任将自己的情况传递给客人,使客人知道主人家里的情况。
这里的信息传递在类种已经 定义好,传递的参数就是类自己。具体看下面例子。
步骤代码实现:
- 创建抽象访问者
//1、创建抽象访问者
//抽象访问者类
public abstract class Action {
//获得某种操作结果
public abstract void getManResult(Man man );
//获得某种操作结果
public abstract void getWomenResult(Women women);
}
- 构建实体访问者
//2、实体访问者
//这里实际上已经写好了接受了主人放回的参数后会怎么做。
public class Success extends Action{
@Override
public void getManResult(Man man) {
System.out.println("男性成功!");
}
@Override
public void getWomenResult(Women women) {
System.out.println("女性成功 !");
}
}
public class Fail extends Action{
@Override
public void getManResult(Man man) {
System.out.println("男人评价失败!");
}
@Override
public void getWomenResult(Women women) {
System.out.println("女人评价失败!");
}
}
- 创建实体类(接受访问),使用了双分配
- 所谓双分配是指不管类怎么变化,我们都能找到期望的方法运行。**双分派意味着得到执
行的操作取决于请求的种类和两个接收者的类型。**也就是你拜访某个朋友,某个朋友把家里的情况描述给你。
//3、创建实体类
public abstract class Person {
public abstract void accept(Action action);
}
//使用了双分配,获得对象进来,把自己传出去。
public class Women extends Person{
//接收到访问对象后,将自己的类放回给访问对象的方法。实现双分配
@Override
public void accept(Action action) {
action.getWomenResult(this);
}
}
public class Man extends Person{
@Override
public void accept(Action action) {
action.getManResult(this);
}
}
- 创建存放被访问者的缓冲层
//4、创建缓冲层
public class ObjectStructure {
//维护一个集合
private LinkedList<Person> persons = new LinkedList<Person>();
//增加进去
public void attach(Person p ) {
persons.add(p);
}
public void detach(Person p) {
persons.remove(p);
}
//显示
public void display(Action action) {
for(Person p:persons) {
p.accept(action);
}
}
}
- 调用
//5、调用
public class Client {
public static void main(String[] args) {
ObjectStructure objectstructure = new ObjectStructure();
objectstructure.attach(new Man());
objectstructure.attach(new Man());
objectstructure.attach(new Man());
Success success = new Success();
objectstructure.display(success);
}
}
访问者模式的注意事项和细节
优点:
- 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
- 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点:
3. 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
4. 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
5. 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.
4、迭代器模式
概述:
一种用于顺序访问集合对象的元素,不需要知道集合对象的底层表示的设计模式。
- 迭代器模式(Iterator Pattern)是常用的设计模式。
- 如果我们的集合元素是用不同的方式实现的,有数组,还有 java 的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
- 提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表
示,即:不暴露其内部的结构。
特点:
提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
实现多种数据结构的遍历而不用了解其内部结构。
角色:
1、 迭代器接口
2、 迭代器具体实现对象
3、 聚合接口(用于将客户端和具体解耦)
4、 具体的聚合类对象
步骤代码实现:
- 实现Iterator接口的方法。
1、创建对象类。
public class Department {
private String name;
private String desc;
public Department(String name, String desc) {
super();
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
- 实现Iterator方法,分情况实现hasNext跟next。
2、实现Iterator方法,分情况实现hasNext跟next。
public class ComputerCollegeIterator implements Iterator{
//这里需要Department,以对应形式存放
Department[] departments;
int position = 0;
public ComputerCollegeIterator(Department[] departments) {
super();
this.departments = departments;
}
@Override
public boolean hasNext() {
if(position>=departments.length||departments[position]==null) {
return false;
}else {
return true;
}
}
@Override
public Object next() {
Department department = departments[position];
position++;
return department ;
}
}
public class InfoCollegeIterator implements Iterator{
List<Department> departmentlist;
int index = -1;
public InfoCollegeIterator(List<Department> departmentlist) {
super();
this.departmentlist = departmentlist;
}
@Override
public boolean hasNext() {
if(index >= departmentlist.size()-1) {
return false;
}else {
index++;
return true;
}
}
@Override
public Object next() {
Department department = departmentlist.get(index);
return department;
}
}
- 创建聚合类接口(用户将客户端与具体解耦)
//3、创建聚合类接口
public interface College {
public String getName();
//增加系的方法
public void addDepartment(String name, String desc);
//返回一个迭代器,遍历
public Iterator createIterator();
}
- 实现聚合类
//4、实现聚合类
public class ComputerCollege implements College {
Department[] departments;
int numOfDepartment = 0 ;// 保存当前数组的对象个数
public ComputerCollege() {
departments = new Department[5];
addDepartment("Java专业", " Java专业 ");
addDepartment("PHP专业", " PHP专业 ");
addDepartment("大数据专业", " 大数据专业 ");
}
@Override
public String getName() {
// TODO Auto-generated method stub
return "计算机学院";
}
@Override
public void addDepartment(String name, String desc) {
// TODO Auto-generated method stub
Department department = new Department(name, desc);
departments[numOfDepartment] = department;
numOfDepartment += 1;
}
@Override
public Iterator createIterator() {
// TODO Auto-generated method stub
return new ComputerCollegeIterator(departments);
}
}
public class InfoCollege implements College {
List<Department> departmentList;
public InfoCollege() {
departmentList = new ArrayList<Department>();
addDepartment("信息安全专业", " 信息安全专业 ");
addDepartment("网络安全专业", " 网络安全专业 ");
addDepartment("服务器安全专业", " 服务器安全专业 ");
}
@Override
public String getName() {
// TODO Auto-generated method stub
return "信息工程学院";
}
@Override
public void addDepartment(String name, String desc) {
// TODO Auto-generated method stub
Department department = new Department(name, desc);
departmentList.add(department);
}
@Override
public Iterator createIterator() {
// TODO Auto-generated method stub
return new InfoCollegeIterator(departmentList);
}
}
- 定义输出类
//5、输出类
public class OutPutImpl {
//学院集合
List<College> collegeList;
public OutPutImpl(List<College> collegeList) {
this.collegeList = collegeList;
}
//遍历所有学院,然后调用printDepartment 输出各个学院的系
public void printCollege() {
//从collegeList 取出所有学院, Java 中的 List 已经实现Iterator
Iterator<College> iterator = collegeList.iterator();
while(iterator.hasNext()) {
//取出一个学院
College college = iterator.next();
System.out.println("=== "+college.getName() +"=====" );
printDepartment(college.createIterator()); //得到对应迭代器
}
}
//输出 学院输出 系
public void printDepartment(Iterator iterator) {
while(iterator.hasNext()) {
Department d = (Department)iterator.next();
System.out.println(d.getName());
}
}
}
- 客户端调用
//6、客户端调用
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建学院
List<College> collegeList = new ArrayList<College>();
ComputerCollege computerCollege = new ComputerCollege();
InfoCollege infoCollege = new InfoCollege();
collegeList.add(computerCollege);
//collegeList.add(infoCollege);
OutPutImpl outPutImpl = new OutPutImpl(collegeList);
outPutImpl.printCollege();
}
}
迭代器模式细节和注意事项:
优点:
- 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
- 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
- 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
- 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式
缺点:
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类
5、观察者模式
概述:
观察者模式的思想类似广播站。当某一用户通过广播频率收听广播时,广播便会将信号传递给该 用户。
广播和用户是一个一对多的关系。
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
特点:
一个对象状态改变给其他对象通知,实现了易用和低耦合,保证高度的协作。
角色:
- 中转者:负责储存订阅的用户以及发送更新数据
- 观察者:相当于广播中的收听用户
类图示例:
在这里想实现的是天气系统更新天气,其他各个订阅频道的接口收到该变化并且更新数据。
步骤代码实现:
- 定义观察者接口
//观察者接口,有观察者来实现
public interface Observer {
public void update(float temperature, float pressure, float humidity);
}
- 定义对应类实现观察者接口
public class BaiduSite implements Observer {
// 温度,气压,湿度
private float temperature;
private float pressure;
private float humidity;
// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
// 显示
public void display() {
System.out.println("===百度网站====");
System.out.println("***百度网站 气温 : " + temperature + "***");
System.out.println("***百度网站 气压: " + pressure + "***");
System.out.println("***百度网站 湿度: " + humidity + "***");
}
}
public class CurrentConditions implements Observer {
// 温度,气压,湿度
private float temperature;
private float pressure;
private float humidity;
// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
// 显示
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
- 定义中转者接口
//接口, 让 WeatherData 来实现
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
- 实现中转者接口
/**
* 类是核心
* 1. 包含最新的天气情况信息
* 2. 含有 观察者集合,使用 ArrayList 管理
* 3. 当数据有更新时,就主动的调用 ArrayList, 通知所有的(接入方)就看到最新的信息
* @author Administrator *
*/
public class WeatherData implements Subject {
private float temperatrue;
private float pressure;
private float humidity;
//观察者集合
private ArrayList<Observer> observers;
//加入新的第三方
public WeatherData() {
observers = new ArrayList<Observer>();
}
public float getTemperature() {
return temperatrue;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void dataChange() {
//调用 接入方的 update
notifyObservers();
}
//当数据有更新时,就调用 setData
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
//调用 dataChange, 将最新的信息 推送给 接入方 currentConditions
dataChange();
}
//注册一个观察者
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
observers.add(o);
}
//移除一个观察者
@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
if(observers.contains(o)) {
observers.remove(o);
}
}
//遍历所有的观察者,并通知
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for(int i = 0; i < observers.size(); i++) {
observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
}
}
}
- 客户端调用
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建一个 WeatherData
WeatherData weatherData = new WeatherData();
//创建观察者
CurrentConditions currentConditions = new CurrentConditions();
BaiduSite baiduSite = new BaiduSite();
//注册到 weatherData
weatherData.registerObserver(currentConditions);
weatherData.registerObserver(baiduSite);
//测试
System.out.println("通知各个注册的观察者, 看看信息");
weatherData.setData(10f, 100f, 30.3f);
weatherData.removeObserver(currentConditions);
//测试
System.out.println();
System.out.println("通知各个注册的观察者, 看看信息");
weatherData.setData(10f, 100f, 30.3f);
}
}
6、中介者模式
概述:
一种是用来降低多个对象和类之间的通信复杂性的设计模式。
特点:
用一个对象来封装一系列的对象交互,使各个对象之间无需显示地相互作用,从而使耦合松散,而且可以独立改变他们之间地交互。
使网状结构变成星型结构。
角色:
1、中介者(管理对象,完成对象操作和任务)
2、实体对象
3、客户端:通过中介者调用实体对象
类图示例:
代码实现:
- 创建抽象类对象
//1、创建抽象实体类
//同事抽象类
public abstract class Colleague {
private Mediator mediator;
public String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public Mediator GetMediator() {
return this.mediator;
}
public abstract void SendMessage(int stateChange);
}
- 创建实体类
//2、创建实体类
public class Curtains extends Colleague {
public Curtains(Mediator mediator, String name) {
super(mediator, name);
// TODO Auto-generated constructor stub
mediator.Register(name, this);
}
@Override
public void SendMessage(int stateChange) {
// TODO Auto-generated method stub
this.GetMediator().GetMessage(stateChange, this.name);
}
public void UpCurtains() {
System.out.println("I am holding Up Curtains!");
}
}
public class CoffeeMachine extends Colleague {
public CoffeeMachine(Mediator mediator, String name) {
super(mediator, name);
// TODO Auto-generated constructor stub
mediator.Register(name, this);
}
@Override
public void SendMessage(int stateChange) {
// TODO Auto-generated method stub
this.GetMediator().GetMessage(stateChange, this.name);
}
public void StartCoffee() {
System.out.println("It's time to startcoffee!");
}
public void FinishCoffee() {
System.out.println("After 5 minutes!");
System.out.println("Coffee is ok!");
SendMessage(0);
}
}
public class TV extends Colleague {
public TV(Mediator mediator, String name) {
super(mediator, name);
// TODO Auto-generated constructor stub
mediator.Register(name, this);
}
@Override
public void SendMessage(int stateChange) {
// TODO Auto-generated method stub
this.GetMediator().GetMessage(stateChange, this.name);
}
public void StartTv() {
// TODO Auto-generated method stub
System.out.println("It's time to StartTv!");
}
public void StopTv() {
// TODO Auto-generated method stub
System.out.println("StopTv!");
}
}
//具体的同事类
public class Alarm extends Colleague {
//构造器
public Alarm(Mediator mediator, String name) {
super(mediator, name);
// TODO Auto-generated constructor stub
//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象中[集合]
mediator.Register(name, this);
}
public void SendAlarm(int stateChange) {
SendMessage(stateChange);
}
@Override
public void SendMessage(int stateChange) {
// TODO Auto-generated method stub
//调用的中介者对象的getMessage
this.GetMediator().GetMessage(stateChange, this.name);
}
}
- 创建中介者抽象类
//3、中介者抽象类
public abstract class Mediator {
//将给中介者对象,加入到集合中
public abstract void Register(String colleagueName, Colleague colleague);
//接收消息, 具体的同事对象发出
public abstract void GetMessage(int stateChange, String colleagueName);
public abstract void SendMessage();
}
- 创建中介者实体类
//4、实体中介者类
//具体的中介者类
public class ConcreteMediator extends Mediator {
//集合,放入所有的同事对象
private HashMap<String, Colleague> colleagueMap;
private HashMap<String, String> interMap;
public ConcreteMediator() {
colleagueMap = new HashMap<String, Colleague>();
interMap = new HashMap<String, String>();
}
@Override
public void Register(String colleagueName, Colleague colleague) {
// TODO Auto-generated method stub
colleagueMap.put(colleagueName, colleague);
// TODO Auto-generated method stub
if (colleague instanceof Alarm) {
interMap.put("Alarm", colleagueName);
} else if (colleague instanceof CoffeeMachine) {
interMap.put("CoffeeMachine", colleagueName);
} else if (colleague instanceof TV) {
interMap.put("TV", colleagueName);
} else if (colleague instanceof Curtains) {
interMap.put("Curtains", colleagueName);
}
}
//具体中介者的核心方法
//1. 根据得到消息,完成对应任务
//2. 中介者在这个方法,协调各个具体的同事对象,完成任务
@Override
public void GetMessage(int stateChange, String colleagueName) {
// TODO Auto-generated method stub
//处理闹钟发出的消息
if (colleagueMap.get(colleagueName) instanceof Alarm) {
if (stateChange == 0) {
((CoffeeMachine) (colleagueMap.get(interMap
.get("CoffeeMachine")))).StartCoffee();
((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
} else if (stateChange == 1) {
((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
}
} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
.UpCurtains();
} else if (colleagueMap.get(colleagueName) instanceof TV) {//如果TV发现消息
} else if (colleagueMap.get(colleagueName) instanceof Curtains) {
//如果是以窗帘发出的消息,这里处理...
}
}
@Override
public void SendMessage() {
// TODO Auto-generated method stub
}
}
- 调用
//5、客户端调用
public class ClientTest {
public static void main(String[] args) {
//创建一个中介者对象
Mediator mediator = new ConcreteMediator();
//创建Alarm 并且加入到 ConcreteMediator 对象的HashMap
Alarm alarm = new Alarm(mediator, "alarm");
//创建了CoffeeMachine 对象,并 且加入到 ConcreteMediator 对象的HashMap
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator,
"coffeeMachine");
//创建 Curtains , 并 且加入到 ConcreteMediator 对象的HashMap
Curtains curtains = new Curtains(mediator, "curtains");
TV tV = new TV(mediator, "TV");
//让闹钟发出消息
alarm.SendAlarm(0);
coffeeMachine.FinishCoffee();
alarm.SendAlarm(1);
}
}
中介者模式注意事项和细节
- 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
- 减少类间依赖,降低了耦合,符合迪米特原则
- 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
4 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意