结构型设计模式目的是将现有的类或结构组合到一起形成更强大的结构。结构型设计模式共7种分别为适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
一、适配器模式
顾名思义适配器模式是将原本不匹配的两个东西适配到一起使用,以三孔插座、两孔插头及插排为例demo如下:
1.类适配器
新建三孔插座类ThreeHolesSocket
public class ThreeHolesSocket {
/**
* 三孔插座输出电流
* @return
*/
public String OutputCurrent(){
return "输出电流";
}
}
新建插排接口PowerSourceAdapter
public interface PowerSourceAdapter {
/**
* 使用插排充电
*/
String charging();
}
两孔插头TwoHolesCharger继承ThreeHolesSocket并实现PowerSourceAdapter将电流进行转换
public class TwoHolesCharger extends ThreeHolesSocket implements PowerSourceAdapter {
@Override
public String charging() {
String current = OutputCurrent();
System.out.println("接到电流:" + current);
// 转换电流返回
return "返回转换后电流";
}
}
新建测试类验证
public class Test {
public static void main(String[] args) {
PowerSourceAdapter powerSourceAdapter = new TwoHolesCharger();
System.out.println(powerSourceAdapter.charging());
}
}
2.对象适配器
由于类是单继承,无法适配其他类型,此时可以将适配器改为对象适配器,在TwoHolesCharger中去除ThreeHolesSocket继承关系,将ThreeHolesSocket传入即可
TwoHolesCharger修改为
public class TwoHolesCharger implements PowerSourceAdapter {
private ThreeHolesSocket threeHolesSocket;
public TwoHolesCharger(ThreeHolesSocket threeHolesSocket) {
this.threeHolesSocket = threeHolesSocket;
}
@Override
public String charging() {
String current = threeHolesSocket.OutputCurrent();
System.out.println("接到电流:" + current);
// 转换电流返回
return "返回转换后电流";
}
}
调用方式改为
public class Test {
public static void main(String[] args) {
PowerSourceAdapter powerSourceAdapter = new TwoHolesCharger(new ThreeHolesSocket());
System.out.println(powerSourceAdapter.charging());
}
}
3.接口适配器
当一个接口中定义方法太多,但又不需要全部实现时,可使用接口适配器。接口适配器依赖于抽象类实现。
新建插排接口PowerSourceAdapter定义两个方法
public interface PowerSourceAdapter {
/**
* 使用插排充电
*/
String charging();
/**
* 其他功能
* @return
*/
String other();
}
新建抽象类实现接口AbstractAdapter
public abstract class AbstractAdapter implements PowerSourceAdapter {
@Override
public String charging() {
return null;
}
@Override
public String other() {
return null;
}
}
新建实现类TwoHolesCharger
public class TwoHolesCharger extends AbstractAdapter {
@Override
public String charging() {
return "插排充电";
}
}
二、桥接模式
桥接模式将抽象部分与它的实现部分分离,使他们都可以独立变化。JDBC就是典型的桥接模式使用。桥接模式中存在抽象类(Abstraction),扩展抽象类(RefinedAbstraction),实现类(Implementor),具体实现类(ConcreteImplementor)。下面以插排的厂家及颜色为例:实现生产插排流程。
新建实现类Color
/**
* 实现类:定义角色必需的行为和属性,供扩展抽象类调用
*
* @author huaisf
*
*/
public interface Color {
/**
* 获取插排颜色
*
* @return
*/
String getColor();
}
新建具体实现类WhiteColor,YellowColor
/**
* 具体实现类:真正实现操作
*
* @author huaisf
*
*/
public class WhiteColor implements Color {
@Override
public String getColor() {
return "白色";
}
}
/**
* 具体实现类:真正实现操作
*
* @author huaisf
*
*/
public class YellowColor implements Color {
@Override
public String getColor() {
return "黄色";
}
}
新建抽象类AbstractSocket
/**
* 抽象类:定义出该角色的行为,同时保存一个对实现化角色的引用
*
* @author huaisf
*
*/
public abstract class AbstractSocket {
protected Color color;
public AbstractSocket(Color color) {
this.color = color;
}
/**
* 生产插排
*/
public abstract void create();
}
新建扩展抽象类BullSocket,TCLSocket
/**
* 扩展抽象类:抽象类的子类,实现父类中的业务方法,并通过组合关系调用实现类中的业务方法。
*
* @author huaisf
*
*/
public class BullSocket extends AbstractSocket {
public BullSocket(Color color) {
super(color);
}
@Override
public void create() {
System.out.println(color.getColor() + "公牛插排");
}
}
/**
* 扩展抽象类:抽象类的子类,实现父类中的业务方法,并通过组合关系调用实现类中的业务方法。
*
* @author huaisf
*
*/
public class TCLSocket extends AbstractSocket {
public TCLSocket(Color color) {
super(color);
}
@Override
public void create() {
System.out.println(color.getColor() + "TCL插排");
}
}
新建测试类Test
public class Test {
public static void main(String[] args) {
// 厂家自由组合生成不同颜色插排
BullSocket bullSocket = new BullSocket(new WhiteColor());
bullSocket.create();
}
}
三、组合模式
组合模式主要是用来描述部分与整体的关系,将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。组合模式中包括抽象组件(Component),叶节点(Leaf),组合节点(Composite)三部分,以文件树为例:
新建抽象组件AbstractFile
/**
* 抽象组件:为组合中所有对象提供定义
*
* @author huaisf
*
*/
public abstract class AbstractFile {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 添加文件结构
*
* @param abstractFile
*/
public abstract void add(AbstractFile abstractFile);
/**
* 执行业务逻辑
*
* @param level
*/
public abstract void print(int level);
}
新建组合节点Folder
/**
* 组合节点:实现Component所有操作,并且持有子节点对象
*
* @author huaisf
*
*/
public class Folder extends AbstractFile {
private List<AbstractFile> abstractFileList = new ArrayList<AbstractFile>();
@Override
public void add(AbstractFile abstractFile) {
abstractFileList.add(abstractFile);
}
public Folder(String name) {
this.setName(name);
}
@Override
public void print(int level) {
String temp = "";
for (int i = 0; i < level; i++) {
temp += "--";
}
System.out.println(temp + getName());
// 遍历文件夹
for (AbstractFile AbstractFile : abstractFileList) {
AbstractFile.print(level + 1);
}
}
}
新建叶节点File
/**
* 叶节点:实现Component中部分操作,该节点为最小节点
*
* @author huaisf
*
*/
public class File extends AbstractFile {
public File(String name) {
this.setName(name);
}
@Override
public void add(AbstractFile abstractFile) {
System.out.println("非目录无法添加下级文件");
}
@Override
public void print(int level) {
String temp = "";
for (int i = 0; i < level; i++) {
temp += "--";
}
System.out.println(temp + getName());
}
}
新建测试类Test整合文件树
public class Test {
public static void main(String[] args) {
// root目录下有tmp目录及rootFile.txt文件,tmp目录下有tmpFile.txt文件
Folder rootFolder = new Folder("root");
Folder tmpFolder = new Folder("tmp");
File rootFile = new File("rootFile.txt");
File tmpFile = new File("tmpFile.txt");
rootFolder.add(rootFile);
tmpFolder.add(tmpFile);
rootFolder.add(tmpFolder);
rootFolder.print(0);
}
}
四、装饰模式
装饰模式目的为动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。装饰模式包括抽象组件(Component),具体实现组件(ConcreteComponent),抽象装饰器(Decorator),具体装饰器(ConcreteDecorator)四部分,以包装插排为例
新建抽象组件Socket
/**
* 抽象组件:定义被装饰对象的行为
*
* @author huaisf
*
*/
public interface Socket {
/**
* 获取插排
*/
void getSocket();
}
新建具体实现组件BullSocket
/**
* 具体实现组件:被装饰对象
*
* @author huaisf
*
*/
public class BullSocket implements Socket {
@Override
public void getSocket() {
System.out.println("获取到公牛插排");
}
}
新建抽象装饰器AbstractDecorator
/**
* 抽象装饰器:定义被装饰对象的行为
*
* @author huaisf
*
*/
public abstract class AbstractDecorator implements Socket {
private Socket socket;
public AbstractDecorator(Socket socket) {
this.socket = socket;
}
@Override
public void getSocket() {
this.socket.getSocket();
}
}
新建具体装饰器PlasticDecorator
/**
* 具体装饰器:实现对象装饰
*
* @author huaisf
*
*/
public class PlasticDecorator extends AbstractDecorator {
public PlasticDecorator(Socket socket) {
super(socket);
}
@Override
public void getSocket() {
super.getSocket();
System.out.println("对插排进行塑料包装");
}
}
新建测试类Test
public class Test {
public static void main(String[] args) {
// 获取包装过后插排
Socket socket = new PlasticDecorator(new BullSocket());
socket.getSocket();
}
}
五、外观模式
外观模式为调用者提供一个统一的接口来访问子系统中的一群接口。其包括外观角色(Facade)与子系统角色(SubSystem)。外观模式代码实现比较简单,也比较常见。
新建子系统ClassA,ClassB
/**
* 子系统实现不同功能
*
* @author huaisf
*
*/
public class ClassA {
public void doSomething() {
System.out.println("classA");
}
}
/**
* 子系统实现不同功能
*
* @author huaisf
*
*/
public class ClassB {
public void doSomething() {
System.out.println("classB");
}
}
新建外观角色Facade
/**
* 外观角色:提供统一接口
* @author huaisf
*
*/
public class Facade {
private static ClassA classA;
private static ClassB classB;
static {
classA = new ClassA();
classB = new ClassB();
}
public void doSomethingA() {
classA.doSomething();
}
public void doSomethingB() {
classB.doSomething();
}
}
新建测试类Test
public class Test {
public static void main(String[] args) {
Facade facade = new Facade();
facade.doSomethingA();
facade.doSomethingB();
}
}
六、亨元模式
亨元模式常用于实现池技术,例如数据库连接池,缓冲池。使用亨元模式可以避免创建大量对象。在亨元模式中存在抽象享元(Flyweight),具体亨元(ConcreteFlyWeight),非共享享元(UnsharedConcreteFlyWeight),享元工厂类(FlyweightFactory)四种角色。
新建抽象享元AbstractDataSource
/**
* 抽象享元:定义对象的外部状态、内部状态、方法等
*
* @author huaisf
*
*/
public abstract class AbstractDataSource {
abstract void print();
}
新建具体享元MySqlDataSource
/**
* 具体享元:对抽象亨元具体实现
*
* @author huaisf
*
*/
public class MySqlDataSource extends AbstractDataSource {
private String key;
public MySqlDataSource(String key) {
this.key = key;
}
@Override
void print() {
System.out.println(key);
}
}
新建亨元工厂DataSourceFactory
/**
* 享元工厂:管理亨元对象,达到复用目的
*
* @author huaisf
*
*/
public class DataSourceFactory {
private static ConcurrentHashMap<String, AbstractDataSource> map = new ConcurrentHashMap<String, AbstractDataSource>();
public static AbstractDataSource getMySqlDataSource(String key) {
AbstractDataSource abstractDataSource = map.get(key);
if (abstractDataSource == null) {
abstractDataSource = new MySqlDataSource(key);
map.put(key, abstractDataSource);
}
return abstractDataSource;
}
public static Integer getSize() {
return map.size();
}
}
新建测试类Test
public class Test {
public static void main(String[] args) {
DataSourceFactory.getMySqlDataSource("key1");
DataSourceFactory.getMySqlDataSource("key1");
DataSourceFactory.getMySqlDataSource("key2");
System.out.println(DataSourceFactory.getSize());
}
}
七、代理模式
代理模式为其他对象提供一种代理以控制对这个对象的访问,比如生活中常见的代理商等,该模式中存在抽象主题类(Subject),具体实现类(RealSubject),代理类(Proxy)。
新建抽象主题类Socket
/**
* 抽象主题类:定义实现类与代理的共同接口方法
*
* @author huaisf
*
*/
public interface Socket {
public void buySocket();
}
新建具体实现类BullSocket
/**
* 具体实现类:将抽象主题类定义的功能做具体实现
*
* @author huaisf
*
*/
public class BullSocket implements Socket {
@Override
public void buySocket() {
System.out.println("工厂卖出插排");
}
}
新建代理类Dealers
/**
* 代理类:在购买者与厂家之间进行代理
*
* @author huaisf
*
*/
public class Dealers implements Socket {
private BullSocket bullSocket;
public Dealers(BullSocket bullSocket) {
this.bullSocket = bullSocket;
}
@Override
public void buySocket() {
System.out.println("代理商到工厂购买插排");
bullSocket.buySocket();
System.out.println("代理商将插排卖给用户");
}
}
新建测试类Test
public class Test {
public static void main(String[] args) {
Dealers dealers = new Dealers(new BullSocket());
dealers.buySocket();
}
}