一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
上一篇文章介绍了设计模式中的创建型模式,感兴趣的同学请移步设计模式(三):初识设计模式
结构型模式
适配器模式(Adapter Pattern)
适配器模式将某个类的接口转换为客户端期望的另一个接口表示,让原本因接口不匹配不能一起工作的两个类可以协同工作,其别名为包装器(Wrapper)。
适配器模式主要分为三类:类适配器模式、对象适配器模式、接口适配器模式,下面主要演示类适配器模式。
代码演示:
//目标接口
interface Target{
public void request();
}
//适配者接口
class Adaptee{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
//类适配器类
class ClassAdapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
优点提高了类的复用,灵活性好。
缺点过多的使用适配器会让系统显得凌乱,结构不易整体把控。
桥接模式(Bridge Pattern)
桥接模式是指将实现和抽象放在两个不同的类层次中,使两个层次可以独立改变,通过使用封装、聚合及继承等行为让不同的类承担不同的职责,从而可以保持各部分的独立性以及应对他们的功能扩展。
代码演示:
// 品牌接口
public interface Brand {
void open();
void close();
void call();
}
// 小米品牌
public class Xiaomi implements Brand{
@Override
public void open() {
System.out.println("小米手机开机");
}
@Override
public void close() {
System.out.println("小米手机关机");
}
@Override
public void call() {
System.out.println("小米手机打电话");
}
}
// Vivo品牌
public class Vivo implements Brand{
@Override
public void open() {
System.out.println("Vivo手机开机");
}
@Override
public void close() {
System.out.println("Vivo手机关机");
}
@Override
public void call() {
System.out.println("Vivo手机打电话");
}
}
// 抽象手机
public abstract class Phone {
// 组合品牌
private Brand brand;
// 构造
public Phone(Brand brand) {
this.brand = brand;
}
protected void open() {
this.brand.open();
}
protected void close() {
this.brand.close();
}
protected void call() {
this.brand.call();
}
}
// 折叠式手机
public class FoldedPhone extends Phone{
public FoldedPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println("折叠样式手机");
}
public void close() {
super.close();
System.out.println("折叠样式手机");
}
public void call() {
super.call();
System.out.println("折叠样式手机");
}
}
//客户端
public class Client {
public static void main(String[] args) {
// 获取折叠式手机 样式+品牌
FoldedPhone phone1 = new FoldedPhone(new Xiaomi());
phone1.open();
phone1.call();
phone1.close();
FoldedPhone phone2 = new FoldedPhone(new Vivo());
phone2.open();
phone2.call();
phone2.close();
}
}
优点抽象和实现的分离。 缺点引入桥接模式会增加对系统的理解和设计难度,要求开发者对抽象层进行编程和设计。
组合模式(Composite Pattern)
组合模式又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示"整体-部分"的层次关系。
代码演示:
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates; //下属
public Employee(String name, String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates() {
return subordinates;
}
}
优点具有较强的扩展性,方便创建出复杂的层次结构
缺点要求较高的抽象性
装饰器模式(Decorator Pattern)
装饰器模式允许向一个现有的对象添加新的功能,同时不改变其结构。
代码演示:
//观赏接口
public interface Look {
public String LookAtPic();
}
//观赏实现类
public class InkPic implements Look
{
@Override
public String LookAtPic()
{
return "欣赏水墨画";
}
}
public class OilPic implements Look
{
@Override
public String LookAtPic() {
return "欣赏油画";
}
}
//装饰器抽象类
public abstract class PicDecorator implements Look
{
private Look look;
public Look getLook() {
return look;
}
public void setLook(Look look) {
this.look = look;
}
public PicDecorator(Look look) {
this.look = look;
}
@Override
public abstract String LookAtPic();
}
//装饰器实现类
public class WoodPicDecorator extends PicDecorator
{
public WoodPicDecorator(Look look) {
super(look);
}
@Override
public String LookAtPic() {
return this.getLook().LookAtPic() + ",木质相框";
}
}
优点动态添加功能
外观模式(Facade Pattern)
外观模式也叫过程模式,它为子系统中的一组接口提供了一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
代码演示:
//观赏接口
public interface Look {
public String lookAtPic();
}
//观赏实现类
public class InkPic implements Look
{
@Override
public String lookAtPic()
{
return "欣赏水墨画";
}
}
public class OilPic implements Look
{
@Override
public String lookAtPic() {
return "欣赏油画";
}
}
//外观类
public class LookMaker {
private Look inkPic;
private Look oilPic;
public LookMaker() {
inkPic = new InkPic();
oilPic = new OilPic();
}
public void showInkPic(){
inkPic.lookAtPic();
}
public void showOilPic(){
oilPic.lookAtPic();
}
}
优点对外屏蔽了子系统的细节,降低了客户端对子系统使用的复杂性,让子系统内部的模块更易维护和扩展。
缺点过多的或不合理的使用外观模式,不利于维护
享元模式(Flyweight Pattern)
享元模式运用共享技术有效地支持大量细粒度的对象,也就是避免创建重复的对象,解决重复对象的内存浪费。
模式的角色及职责:
抽象享元角色:产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现。
具体享元角色:产品的实现类,实现抽象角色定义相关业务。
享元工厂类:用于构建一个池容器(集合),同时提供从池中获取对象方法。
刚刚提到了对象的内部状态和外部状态,内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变。外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
代码演示:
...
private static final HashMap<String, Object> map = new HashMap<>();
public static Object get(String type) {
Object object = map.get(type);
if(object == null) {
object = new Object(type);
circleMap.put(key, object);
}
return object;
}
优点减少了对象的创建,降低系统的内存。
缺点提高了系统的复杂度,划分了外部状态和内部状态。
代理模式(Proxy Pattern)
代理模式为对象提供了一种代理,方便对这个对象进行访问,即通过代理对象访问目标对象。
代理模式有两种,静态代理、动态代理(JDK、Cglib)。
1.静态代理 静态代理在使用时,需要定义接口或父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或是继承相同的父类 代码演示:
//接口
public interface ITeacher{
void teach();
}
//目标类
public class Teacher implements ITeacher{
@Override
public void teach(){
System.out.println("老师授课中...");
}
}
//代理类
public class TeacherProxy implements ITeacher{
private ITeacher target;
public TeacherProxy(ITeacher target){
this.target = target;
}
@Override
public void teach(){
System.out.println("代理操作...");
target.teach();
System.out.println("代理操作...");
}
}
优点在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展
缺点代理对象和目标对象实现相同的接口,一旦接口增加方法,代理对象和目标对象都要维护
2.动态代理
目标对象需要实现接口的使用JDK动态代理,目标对象只是一个单独的对象,并没有实现任何接口的使用Cglib代理。
JDK动态代理实现只需要使用newProxyInstance方法,这个方法需要接收三个参数,完成的写法是:
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
代码演示:
JDK动态代理
//接口类
public interface ITeacher {
void teach();
void sayHello(String name);
}
//目标类
public class Teacher implements ITeacher{
@Override
public void teach() {
System.out.println("老师授课中...");
}
@Override
public void sayHello(String name) {
System.out.println("hello" + name);
}
}
//代理类
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
Object invoke = method.invoke(target, args);
System.out.println("JDK代理完毕");
return invoke;
}
});
}
}
如有不对的地方,欢迎大家指正。