设计模式——适配器模式和外观模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011024652/article/details/82792781

适配器模式和外观模式

本文将分别介绍适配器模式和外观模式。

1、适配器模式

1.1、定义

适配器模式 将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

适配器模式的定义非常易懂,就是将一个接口转换成另一个接口,这样一来就实现了接口的兼容。生活中我们有很多适配器的案例,例如我们请人从香港代购一个手机回来,因为香港使用的插头制式是英式插头,和内地的插座是不兼容的,那么要让手机能够充上电,我们就需要一个转换插头,这样英式插头就能够使用内地的插座了,在这里转换插头就是一个适配器。我们就通过一个案例来介绍一下适配器模式如何使用。

1.2、适配器模式案例

1.2.1、需求

假设我们想模拟读卡器作为内存卡和笔记本电脑之间的适配器,我们将内存卡插入读卡器,然后将读卡器插入笔记本电脑,这样我们就能通过笔记本电脑访问内存卡了。

1.2.2、适配器模式实现

我们可以分析一下需求,需求希望我们能够通过笔记本电脑来存取内存卡上的数据,正常情况下我们通过笔记本电脑只能存取笔记本上的数据,而无法存取内存卡上的数据,因此我们先定义两个接口表示笔记本电脑数据的存取和内存卡数据的存取,它们分别包含读取数据和保存数据的方法。

/**内存卡数据*/
public interface MemoryCard {

	public void readData();
	
	public void writeData();
	
}
/**笔记本电脑数据*/
public interface LaptopData {

	public void readData();
	
	public void writeData();
	
}

接下来我们可以实现内存卡接口,假设我们定义一个手机内存卡类:

public class MobilePhoneMemoryCard implements MemoryCard {

	@Override
	public void readData() {
		System.out.println("从手机内存卡读取数据");
	}

	@Override
	public void writeData() {
		System.out.println("向手机内存卡写数据");
	}

}

需求中是希望我们通过笔记本电脑访问内存卡上的数据,但是笔记本电脑只能访问笔记本中的数据,因此我们需要一个适配器:

/**笔记本电脑适配器*/
//1、首先需要实现想要转换成的接口,在这里就是笔记本电脑的数据
public class LaptopAdapter implements LaptopData {

  	//2、取得适配对象的引用,在这里就是内存卡
	private MemoryCard memoryCard;
	
	public LaptopAdapter(MemoryCard memoryCard) {
		this.memoryCard = memoryCard;
	}
	
	@Override
	public void readData() {
      	//3、在读取数据的方法中,我们使用内存卡的读取方法
		memoryCard.readData();
	}

	@Override
	public void writeData() {
		memoryCard.writeData();
	}

}

这个适配器它实现的是笔记本电脑数据接口,因为笔记本电脑只能访问笔记本的数据,但是它包含一个手机内存卡的引用,因此在读取和保存数据的方法中,它可以调用内存卡的读取和保存方法来完成操作,对于客户来说,这都是透明的,客户仍然认为他访问的是笔记本电脑的数据。

接下来我们就可以使用一个测试类来测试一下适配器了:

public class TestMain {
	
	public static void main(String[] args) {
		MemoryCard memoryCard = new MobilePhoneMemoryCard();
		LaptopData adapter = new LaptopAdapter(memoryCard);
		
		adapter.readData();
		adapter.writeData();
	}

}

运行结果为:

从手机内存卡读取数据
向手机内存卡写数据

可以看到我们能够正确地从笔记本电脑中访问内存卡的数据了。

适配器的类图如下(图片摘自《Head First设计模式》):

在这里插入图片描述

客户通过目标接口调用适配器的方法对适配器发出请求,适配器使用被适配者接口把请求转换成被适配者的一个或多个接口,客户接收到调用的结果,但是并未察觉这一切是适配器在起转换作用,客户和被适配者是解耦的。

2、外观模式

2.1、定义

外观模式 提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。

外观模式的定义也很好理解,在一段业务代码中,我们经常会调用很多的子系统的方法,随着子系统的增多,那么业务代码的复杂度会越来越高,而外观模式它提供了一个高层接口,这个高层接口可以访问所有子系统的代码,而我们业务代码只需要调用这个高层接口就可以了。

2.2、外观模式案例

2.2.1、需求

假设我们想定义一个系统来模拟电脑的启动和关闭过程,其中电脑的启动包含CPU启动、内存启动和硬盘的启动,而电脑的关闭包含硬盘关闭、内存关闭和CPU关闭。

2.2.2、外观模式实现

根据需求因为电脑的启动和关闭包含几个子模块的启动和关闭,我们首先需要定义几个接口表示电脑的CPU、内存和硬盘。

/**CPU*/
public interface CPU {

	public void on();
	
	public void off();
	
}
/**内存*/
public interface Memory {

	public void on();
	
	public void off();
	
}
/**硬盘*/
public interface HardDisk {

	public void on();
	
	public void off();
	
}

这几个接口都定义了开启和关闭方法,接着我们来实现这几个接口:

public class MyCPU implements CPU {

	@Override
	public void on() {
		System.out.println("CPU启动");
	}

	@Override
	public void off() {
		System.out.println("CPU停止");
	}

}

public class MyMemory implements Memory {

	@Override
	public void on() {
		System.out.println("内存启动");
	}

	@Override
	public void off() {
		System.out.println("内存停止");
	}

}

public class MyHardDisk implements HardDisk {

	@Override
	public void on() {
		System.out.println("硬盘启动");
	}

	@Override
	public void off() {
		System.out.println("硬盘停止");
	}

}

在没有接触外观模式之前,我们启动计算机和关闭计算机的时候都需要在客户代码中定义这几个模块,然后分别调用这几个模块的开启和关闭方法,这样会让客户代码难以维护,比如如果我们要新增一个显示器模块,那么就需要修改客户代码,这样频繁修改客户代码显然不是我们想要的。

有了外观模式之后,根据外观模式的定义,我们可以抽象出一个高层接口,由这个高层接口维护所有子系统的访问,例如我们定义一个外观类:

public class ComputerFacade {

	CPU cpu;
	Memory memory;
	HardDisk hardDisk;
	
	public ComputerFacade(CPU cpu, Memory memory, HardDisk hardDisk) {
		this.cpu = cpu;
		this.memory = memory;
		this.hardDisk = hardDisk;
	}
	
	public void on() {
		cpu.on();
		memory.on();
		hardDisk.on();
	}
	
	public void off() {
		hardDisk.off();
		memory.off();
		cpu.off();
	}
	
}

在这个外观类中,我们声明了电脑的几个模块,并在开启和关闭方法中调用对应模块的方法,以后需要新增和减少模块的时候只需要修改外观类即可,无需修改客户代码,客户代码和复杂子系统之间实现了解耦。

我们可以定义一个客户类来测试一下功能:

public class TestMain {

	public static void main(String[] args) {
		CPU cpu = new MyCPU();
		Memory memory = new MyMemory();
		HardDisk hardDisk = new MyHardDisk();
		
		
		ComputerFacade computer = new ComputerFacade(cpu, memory, hardDisk);
		computer.on();
		
		System.out.println("oooooooooooooo");
		computer.off();
	}

}

运行结果如下:

CPU启动
内存启动
硬盘启动
oooooooooooooo
硬盘停止
内存停止
CPU停止

3、总结

本文中介绍的适配器模式和外观模式都很好理解,案例也不难,使用时有以下几个注意点:

  1. 当需要使用一个现有的类而其接口并符合需求时,可以使用适配器,适配器改变接口以符合客户的期望;
  2. 当需要简化并统一一个很大的接口或者一群复杂的接口时,可以使用外观模式,外观模式将客户从一个复杂的子系统中解耦,要实现一个外观,只需要将子系统组合进外观中,然后将工作委托给子系统执行;
  3. 适配器是将一个对象包装起来以改变其接口,而外观则是将一群对象包装起来以简化其接口。

猜你喜欢

转载自blog.csdn.net/u011024652/article/details/82792781