Java学习--设计模式之结构型模式
Posted IVEGOTNOIDEA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习--设计模式之结构型模式相关的知识,希望对你有一定的参考价值。
一、装饰器模式(Decorator Pattern)
1、概念
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
2、简介
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
应用实例:
(1)、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
(2)、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景:
(1)、扩展一个类的功能。
(2)、动态增加功能,动态撤销。
注意事项:可代替继承。
3、实例
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。RedShapeDecorator 是实现了 ShapeDecorator 的实体类。演示类 DecoratorPatternDemo,我们的演示类使用 RedShapeDecorator 来装饰 Shape 对象。
(1)、创建一个接口Shape
public interface Shape { void draw(); }
(2)、创建接口的实现类
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); } }
public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); } }
(3)、创建实现了 Shape 接口的抽象装饰类 ShapeDecorator
public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } public void draw(){ decoratedShape.draw(); } }
(4)、创建扩展了 ShapeDecorator 类的实体装饰类 RedShapeDecorator 。
public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape){ System.out.println("Border Color: Red"); } }
(5)、使用 RedShapeDecorator 来装饰 Shape 对象。
public class DecoratorPatternDemo { public static void main(String[] args) { Shape circle = new Circle(); Shape redCircle = new RedShapeDecorator(new Circle()); Shape redRectangle = new RedShapeDecorator(new Rectangle()); System.out.println("Circle with normal border"); circle.draw(); System.out.println("\\nCircle of red border"); redCircle.draw(); System.out.println("\\nRectangle of red border"); redRectangle.draw(); } }
(6)、演示结果
1 Circle with normal border 2 Shape: Circle 3 4 Circle of red border 5 Shape: Circle 6 Border Color: Red 7 8 Rectangle of red border 9 Shape: Rectangle 10 Border Color: Red
二、外观模式(Facade Pattern)
1、概念
外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
2、简介
意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之相应的接口。
何时使用:
(1)、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。
(2)、定义系统的入口。
如何解决:客户端不与系统耦合,外观类与系统耦合。
关键代码:在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。
应用实例:
(1)、去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。
(2)、JAVA 的三层开发模式。
优点:
(1)、减少系统相互依赖。
(2)、提高灵活性。
(3)、提高了安全性。
缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
使用场景:
(1)、为复杂的模块或子系统提供外界访问的模块。
(2)、子系统相对独立。
(3)、预防低水平人员带来的风险。
注意事项:在层次化结构中,可以使用外观模式定义系统中每一层的入口。
3、实例
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。ShapeMaker 类使用实体类来代表用户对这些类的调用。演示类 FacadePatternDemo,我们的演示类使用 ShapeMaker 类来显示结果。
(1)、创建接口 Shape 。
public interface Shape { void draw(); }
(2)、创建实现了 Shape 接口的实现类。
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Rectangle::draw()"); } }
public class Square implements Shape { @Override public void draw() { System.out.println("Square::draw()"); } }
public class Circle implements Shape { @Override public void draw() { System.out.println("Circle::draw()"); } }
(3)、创建一个外观类 ShapeMaker 。
public class ShapeMaker { private Shape circle; private Shape rectangle; private Shape square; public ShapeMaker() { circle = new Circle(); rectangle = new Rectangle(); square = new Square(); } public void drawCircle(){ circle.draw(); } public void drawRectangle(){ rectangle.draw(); } public void drawSquare(){ square.draw(); } }
(4)、使用外观类画出各种形状。
public class FacadePatternDemo { public static void main(String[] args) { ShapeMaker shapeMaker = new ShapeMaker(); shapeMaker.drawCircle(); shapeMaker.drawRectangle(); shapeMaker.drawSquare(); } }
(5)、演示结果
1 Circle::draw() 2 Rectangle::draw() 3 Square::draw()
三、享元模式(Flyweight Pattern)
1、概念
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
2、简介
意图:运用共享技术有效地支持大量细粒度的对象。
主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
何时使用:
(1)、系统中有大量对象。
(2)、这些对象消耗大量内存。
(3)、这些对象的状态大部分可以外部化。
(4)、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
(5)、系统不依赖于这些对象身份,这些对象是不可分辨的。
如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。
关键代码:用 HashMap 存储这些对象。
优点:大大减少对象的创建,降低系统的内存,使效率提高。
缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
注意事项:
(1)、注意划分外部状态和内部状态,否则可能会引起线程安全问题。
(2)、这些类必须有一个工厂对象加以控制。
3、实例
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory。ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。FlyWeightPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。
(1)、创建一个接口 Shape。
public interface Shape { void draw(); }
(2)、创建接口的实体类。
public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { System.out.println("Circle: Draw() [Color : " + color +", x : " + x +", y :" + y +", radius :" + radius); } }
(3)、创建一个工厂 ShapeFactory ,生成基于给定信息的实体类的对象。
import java.util.HashMap; public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap<>(); public static Shape getCircle(String color) { Circle circle = (Circle)circleMap.get(color); if(circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } }
(4)、使用该工厂,通过传递颜色信息来获取实体类的对象。
public class FlyweightPatternDemo { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for(int i=0; i < 20; ++i) { Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } private static String getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX() { return (int)(Math.random()*100 ); } private static int getRandomY() { return (int)(Math.random()*100); } }
(5)、演示结果
1 Creating circle of color : Black 2 Circle: Draw() [Color : Black, x : 36, y :71, radius :100 3 Creating circle of color : Green 4 Circle: Draw() [Color : Green, x : 27, y :27, radius :100 5 Creating circle of color : White 6 Circle: Draw() [Color : White, x : 64, y :10, radius :100 7 Creating circle of color : Red 8 Circle: Draw() [Color : Red, x : 15, y :44, radius :100 9 Circle: Draw() [Color : Green, x : 19, y :10, radius :100 10 Circle: Draw() [Color : Green, x : 94, y :32, radius :100 11 Circle: Draw() [Color : White, x : 69, y :98, radius :100 12 Creating circle of color : Blue 13 Circle: Draw() [Color : Blue, x : 13, y :4, radius :100 14 Circle: Draw() [Color : Green, x : 21, y :21, radius :100 15 Circle: Draw() [Color : Blue, x : 55, y :86, radius :100 16 Circle: Draw() [Color : White, x : 90, y :70, radius :100 17 Circle: Draw() [Color : Green, x : 78, y :3, radius :100 18 Circle: Draw() [Color : Green, x : 64, y :89, radius :100 19 Circle: Draw() [Color : Blue, x : 3, y :91, radius :100 20 Circle: Draw() [Color : Blue, x : 62, y :82, radius :100 21 Circle: Draw() [Color : Green, x : 97, y :61, radius :100 22 Circle: Draw() [Color : Green, x : 86, y :12, radius :100 23 Circle: Draw() [Color : Green, x : 38, y :93, radius :100 24 Circle: Draw() [Color : Red, x : 76, y :82, radius :100 25 Circle: Draw() [Color : Blue, x : 95, y :82, radius :100
四、代理模式(Proxy Pattern)
1、概念
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
2、简介
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例:
(1)、Windows 里面的快捷方式。
(2)、买火车票不一定在火车站买,也可以去代售点。
(3)、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。
(4)、spring aop。
优点:
(1)、职责清晰。
(2)、高扩展性。
(3)、智能化。
缺点:
(1)、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
(2)、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景:按职责来划分,通常有以下使用场景:
(1)、远程代理。
(2)、虚拟代理。
(3)、Copy-on-Write 代理。
(4)、保护(Protect or Access)代理。
(5)、Cache代理。
(6)、防火墙(Firewall)代理。
(7)、同步化(Synchronization)代理。
(8)、智能引用(Smart Reference)代理。
注意事项:
(1)、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
(2)、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
3、实例
我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。
(1)、创建接口。
public interface Image { void display(); }
(2)、创建接口的实现类。
public class RealImage implements Image { private String fileName; public RealImage(String fileName){ this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadFromDisk(String fileName){ System.out.println("Loading " + fileName); } }
public class ProxyImage implements Image{ private RealImage realImage; private String fileName; public ProxyImage(String fileName){ this.fileName = fileName; } @Override public void display() { if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); } }
(3)、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); //图像将从磁盘加载 image.display(); System.out.println(""); //图像将不再从磁盘加载 image.display(); } }
(4)、演示结果
1 Loading test_10mb.jpg 2 Displaying test_10mb.jpg 3 4 Displaying test_10mb.jpg
结构型模式的讲解到此也就结束了,如有问题,还望各位大佬指正。
以上是关于Java学习--设计模式之结构型模式的主要内容,如果未能解决你的问题,请参考以下文章