1.概述:结构型模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
2.结构型模式简介
模式名称 | 定义 | 简单说明 | 使用频率 |
---|---|---|---|
适配器模式(Adapter) | 将一个类的接口转换成用户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 | 使原本不兼容的事物能够协同工作,而无须修改现有事物的内部结构 | ★★★★ |
桥接模式(Bridge) | 将抽象部分与实现部分分离,使它们都可以独立地变化 | 当事物存在两个独立变化的维度时,将两个变化因素抽取出来形成高层次的关联关系,使原本复杂的类继承结构变得相对简单,极大减少系统中类的个数 | ★★★ |
组合模式(Composite) | 将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和复合对象的使用具有一致性 | 通过面向对象技术来实现对系统中存在的容器对象和叶子对象进行统一操作,且客户端无须知道操作对象是容器还是其成员 | ★★★★ |
装饰模式(Decorator) | 动态地给一个对象添加一些额外的职责,就扩展功能而言,它比生成子类方式更为灵活 | 不使用继承而通过关联关系来调用现有类中的方法,达到复用的目的,并使得对象的行为可以灵活变化 | ★★★ |
外观模式(Facade) | 为子系统中的一组接口提供一个统一的入口,定义一个高层接口,这个接口使得这一子系统更加容易使用 | 为复杂的子系统提供一个统一的入口,简化客户端对多个子系统的访问 | ★★★★★ |
享元模式(Flyweight) | 运用共享技术有效地支持大量细粒度的对象 | 通过共享技术实现对象的重用,大幅节约系统的内存,该模式关心系统的性能与资源利用的情况 | ★ |
代理模式(Proxy) | 为其他对象提供一个代理以控制对这个对象的访问 | 当不能直接访问一个对象时,通过一个代理对象间接访问它 | ★★★★ |
适配器模式重要等级:★★★★
适配器模式难度等级:★★
调用在目标抽象类中定义的业务方法
。现需要设计一个可以模拟各种动物行为的机器人,在机器人中定义了一系列方法,如机器人叫喊方法cry()、机器人移动方法move()等。如果希望在不修改已有代码的基础上使得机器人能够像狗叫一样,像狗跑一样,可以使用适配器模式进行系统设计。
通过分析,可以使用类适配器模式实现该系统设计,实例类图如下图
public interface Robot{
public void cry();
public void move();
}
Robot充当目标抽象角色,客户端针对抽象的Robot类进行编程,在Robot中声明(也可以是实现)了客户端所调用的业务方法,如本实例中的cry()方法和move()方法。
public class Dog{
public void wang(){
System.out.println("狗汪汪叫");
}
public void run(){
System.out.println("狗快快快跑");
}
}
Dog类是一个已存在的具体类,它包含用户所需业务方法的具体实现,如本类中的wang()方法和run()方法,但是方法名等与Target接口不一致,甚至没有该类的源码。
public class DogAdapter extends Dog implements Robot {
@Override
public void cry() {
System.out.println("机器人模仿:");
super.wang();
}
@Override
public void move() {
System.out.println("机器人模仿:");
super.run();
}
}
DogAdapter类是适配器模式的核心类,在此处使用的是类适配器模式,即DogAdapter继承了Dog类并实现了Robot接口,由于DogAdapter实现了Robot接口,因此需要实现在Robot中定义的cry()和move()方法,又因为DogAdapter类继承了Dog类,因此可以继承Dog类中的wang()和run()方法,在cry()中可以调用wang()方法,在move()中可以调用run()方法。
public class Client {
public static void main(String[] args) {
Robot robot = new DogAdapter();
robot.cry();
robot.move();
}
}
由于具体适配器类DogAdapter是Robot的子类,因此系统在运行时可以用子类对象覆盖父类对象,通过DogAdapter调用适配者类Dog中的方法
某系统需要提供一个加密模块,将用户信息(如密码等机密信息)加密之后再存储在数据库中,系统已经定义好了数据库操作类。为了提高开发效率,现需要重用已有的加密算法,这些加密算法封装在一些由第三方提供的类中,有些甚至没有源代码。使用适配器模式设计该加密模块,实现在不修改现有类的基础上重用第三方加密方法。
通过分析,可使用对象适配器模式实现该系统设计,该实例类图如下图
public abstract class DataOperation {
private String password;
public void setPassword(String password)
{
this.password=password;
}
public String getPassword()
{
return this.password;
}
public abstract String doEncrypt(int key,String ps);
}
DataOperation类中包含了抽象方法doEncrypt(),客户端针对抽象类DataOperation进行编程,在客户端代码中调用DataOperation的doEncrypt()实现数据加密。
public class Caesar {
public String doEncrypt(int key,String ps)
{
String es="";
for(int i=0;i<ps.length();i++)
{
char c=ps.charAt(i);
if(c>='a'&&c<='z')
{
c+=key%26;
if(c>'z') c-=26;
if(c<'a') c+=26;
}
if(c>='A'&&c<='Z')
{
c+=key%26;
if(c>'Z') c-=26;
if(c<'A') c+=26;
}
es+=c;
}
return es;
}
}
Caesar类是一个由第三方提供的数据加密类,该类定义为final类,无法继承。因此本实例不能通过类适配器来实现,只能通过对象适配器实现
public class CipherAdapter extends DataOperation {
private Caesar cipher;
public CipherAdapter()
{
cipher=new Caesar();
}
public String doEncrypt(int key,String ps)
{
return cipher.doEncrypt(key,ps);
}
}
CipherAdapter类充当适配器角色,由于Caesar类无法继承,本实例采用对象适配器模式,在CipherAdapter类中定义一个Caesar类型的成员对象,在CipherAdapter类的构造函数中实例化Caesar对象,CipherAdapter与Caesar类之间是组合关联关系。
public class Client2 {
public static void main(String args[]) {
DataOperation dao = new CipherAdapter();
dao.setPassword("sunnyLiu");
String ps = dao.getPassword();
String es = dao.doEncrypt(6, ps);
System.out.println("明文为:" + ps);
System.out.println("密文为:" + es);
}
}