- 写在前面
- 一、适配器模式
- 1.1. 类适配器模式
- 1.2. 对象适配器模式
- 二、桥接模式
- 三、装饰器模式
上一篇我们学习了创建型设计模式
本篇文章通过代码演示的形式,记录结构型设计模式的相关学习总结,包括:适配器模式、桥接模式和装饰器模式
详细内容可参考 Java设计模式、图说设计模式
适配器模式的目的是使接口不兼容的类能够一起工作;其中包含三个角色
- 目标接口:当前系统业务所期待的接口,它可以是抽象类或接口
- 适配者:它是被访问和适配的现存组件库中的组件接口
- 适配器:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者
public interface ElecSocket {
//充电
void recharge();
}
public class SocketAdaptee {
public void socketTransform() {
System.out.println("已转换为当前可用接口,开始充电");
}
}
public class LowPowerAdapter extends SocketAdaptee implements ElecSocket {
@Override
public void recharge() {
System.out.println("使用低电压插座");
socketTransform();
}
}
public class HighPowerAdapter extends SocketAdaptee implements ElecSocket {
@Override
public void recharge() {
System.out.println("使用高电压插座");
socketTransform();
}
}
public class Client {
public static void main(String[] args) {
System.out.println("需要充电");
ElecSocket socket1 = new LowPowerAdapter();
socket1.recharge();
ElecSocket socket2 = new HighPowerAdapter();
socket2.recharge();
}
}
1.2. 对象适配器模式
public interface ElecSocket {
//充电
void recharge();
}
public class SocketAdaptee {
public void socketTransform() {
System.out.println("已转换为当前可用接口,开始充电");
}
}
public class LowPowerAdapter implements ElecSocket {
private SocketAdaptee mAdaptee;
public LowPowerAdapter(SocketAdaptee adaptee) {
mAdaptee = adaptee;
}
@Override
public void recharge() {
System.out.println("使用低电压插座");
mAdaptee.socketTransform();
}
}
public class HighPowerAdapter implements ElecSocket {
private SocketAdaptee mAdaptee;
public HighPowerAdapter(SocketAdaptee adaptee) {
this.mAdaptee = adaptee;
}
@Override
public void recharge() {
System.out.println("使用高电压插座");
mAdaptee.socketTransform();
}
}
public class Client {
public static void main(String[] args) {
System.out.println("需要充电");
SocketAdaptee adaptee = new SocketAdaptee();
ElecSocket socket1 = new LowPowerAdapter(adaptee);
socket1.recharge();
ElecSocket socket2 = new HighPowerAdapter(adaptee);
socket2.recharge();
}
}
二、桥接模式
桥接模式通过分离一个抽象接口和它的实现部分,使得设计可以按两个维度独立扩展。
描述听起来很抽象,我们举个简单的例子:
我们玩游戏经常会要创建角色,角色有不同的种族、职业等属性,假设种族包括人族、精灵,职业包括战士、魔法师,那么我们就能够创造四个不同的职业(2 * 2,不一一列举)。如果通过普通继承的方式,我们需要创建4个子类来分别表示它们,如果属性更多,那么子类的数量会非常庞大。
换一个思路,如果我们只需要创建基础角色,为角色赋予各种属性,是不是就可以更简单呢?
我们以职业为基础维度,为每个职业赋予种族属性
//职业抽象类,包含种族属性
public abstract class Profession {
Ethnicity mEthnicity;
public Profession(Ethnicity mEthnicity) {
this.mEthnicity = mEthnicity;
}
public abstract void createProfession();
}
//魔法师
public class Magician extends Profession {
public Magician(Ethnicity mEthnicity) {
super(mEthnicity);
}
@Override
public void createProfession() {
System.out.println("Create Magician, Ethnicity is " + mEthnicity.createEthnicity());
}
}
//战士
public class Warrior extends Profession {
public Warrior(Ethnicity mEthnicity) {
super(mEthnicity);
}
@Override
public void createProfession() {
System.out.println("Create Warrior, Ethnicity is " + mEthnicity.createEthnicity());
}
}
定义好了职业,我们再来定义种族属性。
//种族类型接口
public interface Ethnicity {
String createEthnicity();
}
//人类
public class Human implements Ethnicity {
@Override
public String createEthnicity() {
return "Human";
}
}
//精灵
public class Elf implements Ethnicity {
@Override
public String createEthnicity() {
return "Elf";
}
}
定义好之后,我们在创建的时候,只需要给每个职业赋予种族属性即可得到对应的角色。
public class Player {
public static void main(String[] args) {
Ethnicity elf = new Elf();
Ethnicity human = new Human();
Profession player1 = new Warrior(human);
Profession player2 = new Magician(human);
Profession player3 = new Warrior(elf);
Profession player4 = new Magician(elf);
player1.createProfession();
player2.createProfession();
player3.createProfession();
player4.createProfession();
}
}
这样,4个玩家就创建了4种角色
Create Warrior, Ethnicity is Human Create Magician, Ethnicity is Human Create Warrior, Ethnicity is Elf Create Magician, Ethnicity is Elf
当职业或种族的类型更多时,使用桥接模式,可以避免创建数量庞大的子类,使我们的代码结构更加清晰简洁。
三、装饰器模式装饰器模式的作用是:在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)。
这个相比桥接模式更容易理解,我们还是举个例子来说明。
路飞刚开始只有橡胶果实一项能力
public interface Luffy {
void skill();
}
//普通路飞
public class OriginalLuffy implements Luffy {
private String mSpecialSkill;
@Override
public void skill() {
System.out.println("基础能力:橡胶果实");
}
}
后期通过训练学会了新技能
//抽象角色
public class SpecialSkills implements Luffy {
Luffy mOriginalLuffy;
public SpecialSkills(Luffy mOriginalLuffy) {
this.mOriginalLuffy = mOriginalLuffy;
}
@Override
public void skill() {
mOriginalLuffy.skill();
}
}
//新技能:霸气
public class Haki extends SpecialSkills {
public Haki(Luffy mOriginalLuffy) {
super(mOriginalLuffy);
}
@Override
public void skill() {
super.skill();
setHaki();
}
public void setHaki() {
System.out.println("增加特殊能力");
System.out.println("特殊能力:霸王色霸气、武装色霸气、见闻色霸气");
}
}
public class LuffyIntroduce {
public static void main(String[] args) {
Luffy luffy1 = new OriginalLuffy();
luffy1.skill();
System.out.println("-----------使用装饰器----------");
Luffy luffy2 = new Haki(luffy1);
luffy2.skill();
}
}
基础能力:橡胶果实 -----------使用装饰器---------- 基础能力:橡胶果实 增加特殊能力 特殊能力:霸王色霸气、武装色霸气、见闻色霸气
这样我们就在不改变原本类结构的情况下,增加了新的功能。



