设计模式全详解——11种行为型模式(上)

本文是学习设计模式后,自己做的笔记。

学习资源有菜鸟教程以及尚硅谷韩顺平图解设计模式

本文是设计模式——11个行为型设计模式的上半篇。

设计模式行为型下半篇


1、模板模式

概述:

可以让一个类的行为或其算法可以在运行时更改的设计模式。

模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。

简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤

特点:

可以让一个类的行为或其算法可以在运行时更改的设计模式。

角色:

1、抽象对象

2、继承实现对象

类图示例:

步骤代码实现:

目标:按照步骤生产豆浆,豆浆可以由不同的材料构成。

  1. 豆浆抽象类,定义生产的主要顺序
//抽象类,表示豆浆
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("第四步:黄豆和配料放到豆浆机去打碎 ");
    }
}


  1. 豆浆实现类,可以有针对性实现不同的方法
    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(" 加入上好的红豆 ");
    }
}

  1. 客户端调用

    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();
        }
    }

模板方法模式的注意事项和细节

  1. 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
  2. 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
  3. 优点:既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步
    骤的实现。
  4. 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
  5. 一般模板方法都加上 final 关键字, 防止子类重写模板方法.
  6. 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理

2、命令模式

概述:

是一种数据驱动的设计模式。

  • 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计

  • 命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。

  • 在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作

  • 通俗易懂的理解:将军发布命令士兵去执行。其中有几个角色:将军(命令发布者)士兵(命令的具体执行者)命令(连接将军和士兵)

  • Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象

特点:

请求以命令的形式包裹在对象中,并传给调用对象。

调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

接触命令发送者跟命令接受者的耦合关系,让对象间的调用更加灵活。

角色:

1、命令类接口

2、命令类实体类(内部聚合接收者类)

3、接收者类

4、命令者(聚合命令类实体)

类图示例:

命令模式类图示例
这里的Controller就是将军的角色,Comand就是命令类,值得注意的是士兵角色需要继承命令类,这里就是为了在创建命令类时可以将控制命令传递过去。

步骤代码实现:

  1. 创建命令接口

//1、命令类接口
//创建命令接口
public interface Command {

	//执行动作
	public void execute();
	//取消动作
	public void undo();
}

  1. 创建命令实现类
//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();
	}

}

  1. 创建命令接收者(士兵的角色)
//3、命令接受处理者

//独立的执行者类
public class LightReceiver {

	public void on() {
		System.out.println("电灯打开了!");
		
	}
	
	public void off() {
		System.out.println("电灯关闭了!");
	}

}


  1. 创建聚合控制器类(将军的角色)
//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();
	}
}

  1. 创建空对象类用于初始化

//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
		
	}

}
  1. 调用

//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();
	
	
}
}

命令模式的注意事项和细节

  1. 发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
  2. 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
  3. 容易实现对请求的撤销和重做
  4. 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
  5. 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
  6. 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发- 反馈机制

3、访问者模式

概述

访问者模式是最复杂的一种设计模式,核心就是要理解一句话:你带着好奇心去朋友家拜访,朋友把家里的情况描述给你,你了解后针对好奇心解决疑惑。这就是设计者模式的整体流程。

一种使用了一个访问者类来改变了元素类的执行算法的设计模式

  • 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
  • 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
  • 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
  • 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决

特点:

封装一些作用与某种数据结构的各元素的操作,可以在不改变数据结构的前提下重新定义作用与这些元素的新操作。

解决数据结构跟操作耦合性问题。

在被访问的类里面加一个对外提供访问者的接口。

在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

角色:

1、抽象访问者:对数据结构进行操作

2、实体访问者

3、抽象元素类:提供一个aceept方法来接受访问者,并且在accep中返回自己的情况。

4、具体元素类

5、ObjectStructure:能枚举他的元素,提供一个高层接口,用来允许访问者访问元素

类图示例:

访问者模式类图示例
这里Element就是主人,Visitor就是客人。

客人来访的时候,主任将自己的情况传递给客人,使客人知道主人家里的情况。

这里的信息传递在类种已经 定义好,传递的参数就是类自己。具体看下面例子。

步骤代码实现:

  1. 创建抽象访问者
//1、创建抽象访问者


//抽象访问者类
public abstract class Action {

	//获得某种操作结果
	public abstract void getManResult(Man man );

	//获得某种操作结果
	public abstract void getWomenResult(Women women);
}
  1. 构建实体访问者
//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("女人评价失败!");
	}

}
  1. 创建实体类(接受访问),使用了双分配
  • 所谓双分配是指不管类怎么变化,我们都能找到期望的方法运行。**双分派意味着得到执
    行的操作取决于请求的种类和两个接收者的类型。**也就是你拜访某个朋友,某个朋友把家里的情况描述给你。

//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);	
	}
	
	

}

  1. 创建存放被访问者的缓冲层

//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);
		}
	}
}
  1. 调用
//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);
	}
}

访问者模式的注意事项和细节

优点:

  1. 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
  2. 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

缺点:
3. 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
4. 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
5. 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.

4、迭代器模式

概述:

一种用于顺序访问集合对象的元素,不需要知道集合对象的底层表示的设计模式。

  • 迭代器模式(Iterator Pattern)是常用的设计模式
  • 如果我们的集合元素是用不同的方式实现的,有数组,还有 java 的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
  • 提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表
    示,即:不暴露其内部的结构

特点:

提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

实现多种数据结构的遍历而不用了解其内部结构。

角色:

1、 迭代器接口
2、 迭代器具体实现对象
3、 聚合接口(用于将客户端和具体解耦)
4、 具体的聚合类对象

步骤代码实现:

  1. 实现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;
	}
	
}
  1. 实现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;
	}
}
  1. 创建聚合类接口(用户将客户端与具体解耦)

//3、创建聚合类接口

public interface College {
	
	public String getName();
	
	//增加系的方法
	public void addDepartment(String name, String desc);
	
	//返回一个迭代器,遍历
	public Iterator  createIterator();
}

  1. 实现聚合类
//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);
	}

}
  1. 定义输出类

//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());
		}
	}
	
}

  1. 客户端调用
//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();
	}

}



迭代器模式细节和注意事项:

优点:

  1. 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
  2. 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
  3. 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
  4. 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式

缺点:

每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类

5、观察者模式

概述:

观察者模式的思想类似广播站。当某一用户通过广播频率收听广播时,广播便会将信号传递给该 用户。

广播和用户是一个一对多的关系。

观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

特点:

一个对象状态改变给其他对象通知,实现了易用和低耦合,保证高度的协作。

角色:

  1. 中转者:负责储存订阅的用户以及发送更新数据
  2. 观察者:相当于广播中的收听用户

类图示例:

观察者模式类图示例
在这里想实现的是天气系统更新天气,其他各个订阅频道的接口收到该变化并且更新数据。

步骤代码实现:

  1. 定义观察者接口
    //观察者接口,有观察者来实现
    public interface Observer {
        public void update(float temperature, float pressure, float humidity);
    }
  1. 定义对应类实现观察者接口
    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 + "***");
        }
    }
  1. 定义中转者接口
    //接口, 让 WeatherData 来实现
    public interface Subject {
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyObservers();
    }
  1. 实现中转者接口
    /**
     * 类是核心
     * 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);
            }
        }
    }

  1. 客户端调用

    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. 创建抽象类对象
//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);
}

  1. 创建实体类
//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);
	}

}

  1. 创建中介者抽象类
//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();
}

  1. 创建中介者实体类

//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

	}

}
  1. 调用
//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);
	}

}

中介者模式注意事项和细节

  1. 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
  2. 减少类间依赖,降低了耦合,符合迪米特原则
  3. 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
    4 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值