设计模式可以说针对大多数的代码可以进行优化在简化而形成代码的健壮,很多涉及到算法用设计模式时也很多,需要看设计模式思维导图在上一个创建型模式中
今天带大家了解一下设计模式的结构型模式,结构性模式也可以说两个不同接口或类与接口之间互相搭建的桥梁
类结构型模式:关心类的组合,由多个类总成的强大系统,在类结构型模式一般存在于继承与实现的关系
对象结构型模式:关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法,更符合“合成复用原则”(说白了把对象作为形参,操作时实现复用的,添加父类时更可以体现出多态的表现)
一、 结构型模式之适配器设计模式
适配器设计模式(Adapter pattern):类与接口之间的方法操作,可以使用多个接口中的方法进行对当前类的优化,当前适配器作为两个不同接口的桥梁,他结合两个独立接口的功能
又称包装器(Wrapper),既可以作为类结构型模式,也可以作为对象结构型模式
- 类适配器模式:适配器类与适配者类是继承关系,因为Java不支持多重继承,因此该模式下目标抽象类只能是接口。
- 对象适配器:适配器类与适配者类是关联关系(也可以称为委派关系),即含有适配者类的成员变量
/**
* 适配器接口
* 定义媒体播放器类型
* 用于适配器实现类优化其他常见媒体播放器实现类
*/
public interface MediaPlayer {
void play(String player , String fileName);
}
适配器实现类,处理常用播放器
/**
* 适配器实现类
* 匹配播放器的适配器
* 处理传入播放器类型返回对应播放器的播放文件
*/
public class AdapterMedia implements MediaPlayer {
private CommonMediaPlayer commonMediaPlayer;
//获取播放器
public AdapterMedia(String player) {
if (player.equalsIgnoreCase("mp4")) {
commonMediaPlayer = new Mp4Player();
} else if (player.equalsIgnoreCase("gif")) {
commonMediaPlayer = new GIFPlayer();
}
}
//获取播放器文件
@Override
public void play(String player, String fileName) {
if (player.equalsIgnoreCase("mp4")) {
commonMediaPlayer.playerMp4(fileName);
} else if (player.equalsIgnoreCase("gif")) {
commonMediaPlayer.playerGIF(fileName);
}
}
}
拓展适配器处理其他播放器的类型
/**
* 拓展适配器处理播放器的类型
* 处理其他播放器
*/
public class AdapterRestMedia implements MediaPlayer {
private MediaPlayer mediaPlayer;
@Override
public void play(String player, String fileName) {
//处理avi播放器
if (player.equalsIgnoreCase("avi")) {
System.out.println("AVI player file ; name = " + fileName);
} else if (player.equalsIgnoreCase("mp4") || player.equalsIgnoreCase("gif")) {
//处理常用播放器
mediaPlayer = new AdapterMedia(player);
mediaPlayer.play(player, fileName);
} else {
//处理其他播放器
System.out.println(player + " player file ; name = " + fileName);
}
}
}
定以常用播放器
/**
* 定义常见媒体播放器
*/
public interface CommonMediaPlayer {
void playerMp4(String fileName);
void playerGIF(String fileName);
}
/**
* MP4播放器类型播放
*/
public class Mp4Player implements CommonMediaPlayer{
@Override
public void playerMp4(String fileName) {
System.out.println("Mp4 player file ; name = " + fileName);
}
@Override
public void playerGIF(String filName) {
//不属于当前播放器不需要做
}
}
/**
* GIF播放器类型播放
*/
public class GIFPlayer implements CommonMediaPlayer{
@Override
public void playerMp4(String fileName) {
//不属于当前播放器
}
@Override
public void playerGIF(String fileName) {
System.out.println("GIF player file ; name = " + fileName);
}
}
结果显示
优缺点
可针对于在不修改适配器以及常用播放器的接口时,可进行拓展,符合"开闭设计原则"
二、结构型模式之桥接模式
桥接模式(Bridge pattern):是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响
将接口中的方法作用于抽象类中,继承的类可以操作与接口中的方法,也可使用抽象类中的方法,可为接口方法实现化解耦,解决了继承类每次都需再次定义接口才能使用与接口方法
桥接接口
/**
* 负责画矩形接口
*/
public interface DrawRectangle {
void draw(int x , int y , int corner);
}
画长方形实现类
/**
* 画长方形实现类
*/
public class Rectangle implements DrawRectangle{
@Override
public void draw(int x, int y, int corner) {
System.out.println("rectangle draw {x = " + x + " y = " + y + " corner = " + corner + "}");
}
}
画正方形实现类
/**
* 画正方形接口
*/
public class Square implements DrawRectangle{
@Override
public void draw(int x, int y, int corner) {
System.out.println("Square draw {x = " + x + " y = " + y + " corner = " + corner + "}");
}
}
搭接桥接接口的主要抽象类
/**
* 定义桥接抽象类
* 作为桥接模式的主要抽象类
* 可解决为继承类实现与接口之间进行解耦的操作
*/
public abstract class Shape {
protected DrawRectangle drawRectangle;
protected Shape(DrawRectangle drawRectangle) {
this.drawRectangle = drawRectangle;
}
protected abstract void draw();
}
桥接继承类
/**
* 处理画矩形方法
* 作为桥接的继承类
* 主要负责画矩形
*/
public class ExRectangle extends Shape {
private int x, y, corner;
protected ExRectangle(int x, int y, int corner, DrawRectangle drawRectangle) {
super(drawRectangle);
this.x = x;
this.y = y;
this.corner = corner;
}
//找父类中接口对象进行画矩形方法
@Override
protected void draw() {
drawRectangle.draw(x, y, corner);
}
}
结果显示
优缺点
通过将另一维度抽象,并使用关联关系,一定程度上进行了解耦,也 满足了"合成复用原则",大大减少了因静态抽象继承结构可能带来的类的数量
加上新增扩充抽象类或具体实现类均不需要修改其他任何代码,因此很好的符合了"依赖倒置原则"与"开闭原则"
继承接口时,也可不修改抽象类,进行添加画矩形实现类,进而抽象类的继承类也可操作与接口新增的方法,进而体现复用性强
三、结构型模式之过滤器模式
过滤器设计模式(Filter pattern):这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准,以多个结果获取最终结果
代码实现
定义car类
//定义car类
public class Car {
private String name;
public Car() {
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
public Car(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
定义过滤标准
//定义过滤标准
public interface FilterCar {
List<Car> criteria(List<Car> cars);
}
标准规则
/**
* 过滤匹配当前对象的
* 可进行拓展过滤规则
*/
public class CarFilter implements FilterCar{
@Override
public List<Car> criteria(List<Car> cars) {
List<Car> list = new ArrayList<>();
for (Car car : cars) {
if (car.getName().equalsIgnoreCase("BaoMa")) {
list.add(car);
}
}
return list;
}
}
结果显示
优缺点
多个标准获取单一符合标准,可在过滤规则中进而拓展标准规则,符合"开闭原则"
四、结构型模式之组合模式
组合模式(Composite Pattern):两个类之间有着重要性的关联,类似于一个整体->部分之间的关系,个体需要包含整体维持对应功能,组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构,部分类的生命周期在于整体类
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
代码实现
/**
* 定义员工类
* 类中定义集合,进行添加其他部门员工
* 进而体现出集合与当前类之间存在着个体与整体之间的关系
*/
public class Employee {
private String name;
private Integer age;
private Double Salary;
private List<Employee> list;
public Employee(String name, Integer age, Double salary) {
this.name = name;
this.age = age;
this.Salary = salary;
list = new ArrayList<>();
}
public void add(Employee e){
list.add(e);
}
public void remove(Employee e) {
list.remove(e);
}
public List<Employee> getList() {
return list;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", Salary=" + Salary +
", list=" + list +
'}';
}
}
实现整体与个体组合模式的关系
/**
* 整体类中包含部分部门,部门包含员工
* 整体与个体之间的生命周期关系
*/
public class EmpTest {
public static void main(String[] args) {
Employee employee = new Employee("CEO", 28, 10000.0);
Employee footEmployee = new Employee("foot", 26, 5000.0);
Employee tallEmployee = new Employee("tall", 24, 4000.0);
Employee em = new Employee("CTO", 30, 10000.0);
Employee em1 = new Employee("head", 25, 5000.0);
Employee em2 = new Employee("tall", 29, 8000.0);
employee.add(em);
employee.add(footEmployee);
footEmployee.add(tallEmployee);
em.add(em1);
em.add(em2);
employee.getList().forEach(System.out::println);
}
}
优缺点
- 优点:1、高层模块调用简单。 2、节点自由增加。
- 缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
部分基于整体而实现的结果,没遵守依赖倒置原则,依赖于抽象类或者接口对应的展示数据
五、结构型模式之装饰器模式
装饰器设计模式(Decorator Pattern):允许增加方法的可复用性,在不改变原对象中的结构情况进而增强原对象中的方法
这种方法在不改变原对象方法的情况下进而拓展新的方法
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能
代码实现
装饰类
/**
* 定义装饰接口
*/
public interface Shape {
void draw();
void noDraw();
}
被装饰类
/**
* 被装饰类
*/
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("Circle::draw()");
}
//不需要增强的方法
@Override
public void noDraw() {
System.out.println("Circle::noDraw()");
}
}
增强被装饰类方法,父类实现装饰接口的全部方法
/**
* 增强被装饰类
* 定义实现装饰类接口的全部方法
* 子类从而增强被装饰类的方法
* 不写子类继承的话容易出现冗余不增强方法也需要写
*/
public class DecoratorShape implements Shape {
//声明被装饰类引用
protected Shape shape;
//外部传入被装饰类对象
protected DecoratorShape(Shape shape) {
this.shape = shape;
}
//被装饰类所有方法
@Override
public void draw() {
shape.draw();
}
@Override
public void noDraw() {
shape.noDraw();
}
}
子类进行增强被装饰类方法
/**
* 增强被增强类
*/
public class ExDecoratorShape extends DecoratorShape{
protected ExDecoratorShape(Shape shape) {
super(shape);
}
@Override
public void draw() {
super.draw();
setDrawCircleBorder(shape);
}
//增强方法
public void setDrawCircleBorder(Shape shape) {
System.out.println("border color : red");
}
}
优缺点
- 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能
- 缺点:多层装饰比较复杂(明确增强过后再次继承增强就不可能进行增强,类与类之间只能是单继承)
六、结构型模式之外观设计模式
外观设计模式(Facade Pattern):隐藏系统的复杂性,向客户端提供一个客户端的访问客户端的接口
这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性
进而体现出依赖关系,类与类之间的依赖关系,当前类需要使用外部类进行处理当前类中的方法
常用场景:Java的三层架构,在Dao层进行处理数据访问层访问数据库的数据,业务层进行调用数据访问层进行处理业务层的代码方法
代码实现
public interface Shape {
void draw();
}
//菱形
public class Ellipse implements Shape{
@Override
public void draw() {
System.out.println("Ellipse::draw()");
}
}
//圆形
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
外观设计模式的主要类,进而提高了图形的实现类的安全性,使图形实现类更加灵活
/**
* 主要外观设计模式类
* 节省了类与类之间的依赖性,提高安全性
* 外观设计模式主要体现于设计三层架构时
* 调用其他接口的实现类方法处理当前类的方法
*/
public class FacadeShape {
private Circle circle;
private Ellipse ellipse;
public FacadeShape() {
circle = new Circle();
ellipse = new Ellipse();
}
public void drawCircle() {
circle.draw();
}
public void drawEllipse() {
ellipse.draw();
}
}
优缺点
- 优点:减少系统的依赖性,提高灵活性,提高安全性
- 缺点:不符合开闭原则,增强原方法时很困难,继承或重写都不合适,在三层架构中进行继承需要拓展的方法时,已经确定好对象时,更改是就会发生其他方法的改变
七、结构型模式之享元模式
享元设计模式(Flyweight Pattern):主要用于减少创建对象的数量,以减少内存占用和提高性能
这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
减少创建对象的占用资源,以及JVM虚拟机销毁时进而多次销毁不必要的对象
代码实现
public class Square implements Shape{
private String color;
private int x;
private int y;
private int corner;
public Square(String color) {
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setCorner(int corner) {
this.corner = corner;
}
@Override
public void draw() {
System.out.println("Square {x = "+x+", y = "+y+", corner = "+corner+", color = "+color+"}");
}
}
减少对象的类,类似于工厂设计模式
/**
* 享元设计模式进行创建独享类似于工厂设计模式
* 利用外部传参的方式进而添加在map集合中进行返回当前对象
*/
public class FactoryShape {
static Map<String,Object> map = new HashMap<>();
public static Shape getShape(String color) {
//获取传入的颜色参数,转换为实现类
Square square = (Square)map.get(color);
if (square == null) {
square = new Square(color);
//形参作为键,图形作为值
map.put(color,square);
}
return square;
}
}
结果展示
优缺点
- 优点:大大减少对象的创建,降低系统的内存,使效率提高
- 缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱,简单来说就是没工厂设计模式设计简单,而不复用,工厂设计模式增加了系统的内存,效率一般,体现效率情况可以通过线程来试验以及synchronized
八、结构型模式之代理模式
代理设计模式(proxy pattern):一个类代表另外一个类的功能,增强被代理类的方法
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口
代码实现
//代理类
public interface StaticProxy {
void display();
}
//被代理类
//被代理类
public class EnhanceProxy implements StaticProxy {
private String fileName;
public EnhanceProxy(String fileName) {
this.fileName = fileName;
client(fileName);
}
@Override
public void display() {
System.out.println("display : " + fileName);
}
public void client(String fileName) {
System.out.println("client : " + fileName);
}
}
增强被代理类对象
/**
* 增强被代理类对象
*/
public class ImplProxy implements StaticProxy{
private EnhanceProxy enhanceProxy;
private String fileName;
public ImplProxy(String fileName) {
this.fileName = fileName;
}
//创建被增强类对象使用被增强类方法进而增强
@Override
public void display() {
if (fileName == null) {
//创建对象触发方法
enhanceProxy = new EnhanceProxy(fileName);
}
enhanceProxy.client(fileName);
}
}
优缺点
- 优点:职责清晰。 2、高扩展性。 3、智能化。
- 缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
在代理类中还有一个动态代理类设计模式,更加简单方便好拓展
Proxy类中的newProxyInstance方法,可针对于某个方法进而增强
增强connection方法中的close
Connection connectionProxy = (Connection) Proxy.newProxyInstance(
//4.3.1 获得被代理类的类加载器
connection.getClass().getClassLoader(),
//4.3.2 容易出现类型转换异常,
//connection.getClass().getInterfaces()获得到的接口数组是com.mysql.jdbc.Connection继承的Connection
//要转换为java.sql.Connection中的Connection会出现转换类型错误
new Class[] {com.mysql.jdbc.Connection.class},
(proxy, method, args) -> {
//4.3.3 拿到原方法需要增强的方法名
Object invoke = null;
//判断增强的方法名是否与原方法名是否一致
if ("close".equals(method.getName())) {
//如果是一个close方法将代理增强连接对象归还给集合中
//5. 归还连接
invoke = linkedList.add(connection);
} else {
//不是close就执行原有的连接池方法
invoke = method.invoke(connection, args);
}
return invoke;
});
//返回增强代理类连接对象close方法,
return connectionProxy;
}
感谢大家欣赏,如有大体的细节没想到的请大家指出 Everyone Good Night!!!