设计模式学习笔记--适配器(Adapter)模式


写在模式学习之前


       什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式;每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案;当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式。

       设计模式就是抽象出来的东西,它不是学出来的,是用出来的;或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以“模式专家”的角度来看,都是最佳的设计,不得不说是“最佳的模式实践”,这是因为你积累了很多的实践经验,知道“在什么场合代码应该怎么写”,这本身就是设计模式。

       有人说:“水平没到,学也白学,水平到了,无师自通”。诚然,模式背熟,依然可能写不出好代码,更别说设计出好框架;OOP理解及实践经验到达一定水平,同时也意味着总结了很多好的设计经验,但"无师自通",却也未必尽然,或者可以说,恰恰是在水平和经验的基础上,到了该系统的学习一下“模式”的时候了,学习一下专家总结的结果,印证一下自己的不足,对于提高水平还是很有帮助的。

       本系列的设计模式学习笔记,实际是对于《Java与模式》这本书的学习记录。


适配器(Adapter)模式定义


适配器模式把一个类的接口(源)变换成客户端所期待的另一种接口(目的),从而使 原本 因接口不匹配而无法在一起工作的两个类能够在一起工作。

名称的由来:

就像变压器,把一种电压变换成另一种电压。美国的生活用电110 V,中国的220 V,在中国使用美国的电器,就必须有一个能把220 V电压转换成110 V电压的变压器。而这正像是本模式所做的事,因此此模式也常常被称为变压器模式。

适配器模式的两种形式:

适配器模式有“类的适配器模式”和“对象的适配器模式”两种不同的形式。


类的适配器模式


在这种方式中,适配器(Adapter)和源(Adaptee)是继承的关系。


模式所涉及的角色有:

(1)目标(Target)角色:这就是所期待得到的接口。注意,由于这里讨论的是类适配器模式,因此目标不可以是类。

(2)源(Adaptee)角色:现有需要适配的接口。

(3)适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

代码实现:

interface Target
{
	void sampleOp1();	//源类有这个方法
	void sampleOp2();
}
class Adaptee
{
	public void sampleOp1(){};
}
class Adapter extends Adaptee implements Target
{
	public void sampleOp2(){};	//由于源类没有这个方法,因此适配器类补充上这个方法
}

对象的适配器模式


在这种方式中,适配器(Adapter)和源(Adaptee)是委派的关系,“适配器”委派“源”,可以通过构造函数或者set方法把“源”传入适配器。


模式所涉及的角色有:

(1)目标(Target)角色:这就是所期待得到的接口。目标也可以是具体的或抽象的类。

(2)源(Adaptee)角色:现有需要适配的接口。

(3)适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

代码实现:

interface Target
{
	void sampleOp1();	//源类有这个方法
	void sampleOp2();
}
class Adaptee
{
	public void sampleOp1(){};
}
class Adapter implements Target
{
	private Adaptee adaptee;
	public Adapter(Adaptee adaptee)
	{
		super();
		this.adaptee = adaptee;
	}
	//源类有这个方法,直接委派
	public void sampleOp1()
	{
		adaptee.sampleOp1();
	}
	public void sampleOp2(){};	//由于源类没有这个方法,因此适配器类补充上这个方法
}

在什么情况下使用适配器模式


(1)系统需要使用现有的类,而此类的接口不符合系统的需要。

(2)想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂的接口。

(3)在设计里,如果需要改变多个已有的子类的接口,对于“类的适配器模式”,需要做多个适配器类,分别继承各个子类,这不实际,更经常使用“对象的适配器模式”。


JDK1.2之前没有Iterator(集合迭代器),只有Enumeration,如下代码演示一个例子,提供一个“从Enumeration到Iterator”适配器。

import java.util.*;
public class Enumeration2Iterator implements Iterator
{
	Enumeration enu;
	public Enumeration2Iterator(Enumeration enu)
	{
		this.enu = enu;
	}
	public boolean hasNext()
	{
		return enu.hasMoreElements();
	}
	public Object next()
	{
		return enu.nextElement();
	}
	public void remove()
	{
		throw new UnsupportedOperationException();
	}
}

缺省适配(Default Adapter)模式


(1)适配器模式还有一个特例,被称作“缺省适配(Default Adapter)模式”,“缺省适配模式”为一个接口提供缺省实现,这里子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。缺省适配模式,是一种平庸化的适配器模式,它对目标接口提供了“平庸化”的实现或者空实现。

(2)缺省适配模式的中心是一个缺省适配类。这个类应当是抽象类,因为这个类不应当实例化,它的实例化也没有用处。

(3)但是缺省适配类所提供的方法却应当是具体的方法,而不是抽象的方法,因为按照模式的用意,这些方法之所以存在,就是为了提供默认实现,以便缺省适配类的具体子类可以按照需要只实现需要实现的方法,忽略不需要实现的方法。

代码演示:

interface 和尚
{
	void 吃斋();
	void 念经();
	void 习武();
}
//这个抽象的天孤星就是一个适配器类,鲁智深借助于“适配器模式”实现了“和尚”接口,达到剃度的目的
abstract class 天孤星 implements 和尚
{
	public void 吃斋() {}
	public void 念经() {}
	public void 习武() {}
}
class 鲁智深 extends 天孤星
{
	public void 习武()
	{
		//do something
	}
}

更多了解


(1)如下代码所示的CollectionData也是一个适配器设计模式的实例,它将Generator适配到CollectionData的构造器上。Java编程思想的作者Bruce Eckel认为,这也许并非是适配器的严格定义,但它符合适配器思想的基本精神。

(2)代码如下

import java.util.*;
//Generator是个工具类,用于实例化对象的
interface Generator<T>
{
	T next();
}
class BasicGenerator<T> implements Generator<T>
{
	private Class<T> type;
	public BasicGenerator(Class<T> type)
	{
		this.type = type;
	}
	public T next()
	{
		try
		{
			return type.newInstance();
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}
	public static <T> Generator<T> create(Class<T> type)
	{
		return new BasicGenerator<T>(type);
	}
}
//CollectionData是个适配器类,用于把Generator适配到CollectionData上
class CollectionData<T> extends ArrayList<T>
{
	public CollectionData(Generator<T> gen,int quality)
	{
		for(int i=0;i<quality;i++)
		{
			add(gen.next());
		}
	}
	public static <T> CollectionData<T> list(Generator<T> gen,int quality)
	{
		return new CollectionData<T>(gen,quality);
	}
}


结构模式(Structural Pattern)小结


结构模式(Structural Pattern)一共有七种,分别是:适配器模式、装饰模式、合成模式、代理模式、享元模式、门面模式、桥梁模式。

大致总结如下:

 最大特点典型应用
适配器模式利用对象的功能,并转换其接口日常工作,入目尽是适配器,DAO适配,Cache功能适配,等等
装饰模式对象层面的功能增强,接口不变Java I/O类库的设计
合成模式树枝、叶子同样对待分类树、权限树等
代理模式代表人WebService 的本地代理,权限访问代理,引用计数代理等
享元模式共享对象,减小内存占用编译器系统,Java String
门面模式统一对外接口,方便调用基于SOA框架编程中,不同系统之间的接口
桥梁模式解耦大多数的驱动器,包括JDBC Driver

ESP32-S3在STA模式下设置静态IP通常涉及到配置网络接口的接口配置结构体,比如`esp_netif_t`。以下是一个基本步骤: 1. 首先,你需要在你的应用程序初始化阶段包含必要的头文件,如`esp_wifi.h`和`esp_netif.h`。 ```c #include "esp_wifi.h" #include "esp_netif.h" ``` 2. 定义你的静态IP、子网掩码、默认网关和DNS服务器地址。例如: ```c static const char* ssid = "your_SSID"; static const char* password = "your_PASSWORD"; static ip4_addr_t static_ip = { IP4_ADDR(192, 168, 1, 100) }; // 你的静态IP static ip4_addr_t subnet_mask = { IP4_ADDR(255, 255, 255, 0) }; static ip4_addr_t gateway = { IP4_ADDR(192, 168, 1, 1) }; static ip4_addr_t dns_server = { IP4_ADDR(8, 8, 8, 8)}; // 示例DNS服务器地址 ``` 3. 初始化WiFi模块,并连接到指定的SSID: ```c esp_err_t ret = esp_wifi_init(); if (ret == ESP_OK) { wifi_config_t wifi_config = { .sta = { .ssid = ssid, .password = password, .bssid_set = false, // 如果你知道AP的BSSID可以设置为true }, }; ret = esp_wifi_set_mode(WIFI_MODE_STA); if (ret == ESP_OK) { ret = esp_wifi_start(); if (ret == ESP_OK) { // 等待WiFi连接成功 while (!esp_wifi_get_connect_status() == WIFI_STATUS_CONNECTED) { vTaskDelay(pdMS_TO_TICKS(500)); } } } // 连接成功后再配置静态IP } ``` 4. 创建并配置静态IP网络接口: ```c esp_netif_create StaIf, NULL, &espnetif sta_if; if (esp_netif_create_data斯塔If(&sta_if)) { esp_netif_set_ip4(&sta_if, &static_ip, &subnet_mask, &gateway); esp_netif_set_dhcp_client_data(&sta_if, NULL); // 关闭DHCP服务,使用静态IP esp_netif_set_dns_server_num(&sta_if, 1, &dns_server); esp_netif_start(&sta_if); } // 然后你可以开始发送和接收数据包了 ``` 记得检查错误代码`esp_err_t`,处理可能出现的问题。此外,如果ESP32-S3需要访问互联网,你还可能需要配置路由器的端口转发规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值