原创

JAVA设计模式(篇六)

温馨提示:
本文最后更新于 2022年10月27日,已超过 918 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

九-装饰模式

在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等。在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以采用装饰模式来实现。

1.装饰模式的定义与特点

1. 装饰模式定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

2. 优点

  • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
  • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

3. 缺点:

  • 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

2. 模式的结构和实现

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。

装饰模式由,抽象构件角色具体构件角色抽象装饰角色具体装饰角色 组成

1. 模式的结构

  • 抽象构件角色: 定义一个抽象接口以规范准备接收附加责任(额外功能)的对象。
  • 具体构件角色: 实现抽象构件,通过装饰角色为其添加一些职责(功能)
  • 抽象装饰角色:继承抽象构件,并包含具体构件的实例,通过其子类扩展具体构件的功能
  • 具体装饰角色: 继承抽象装饰角色,实现抽象装饰的相关方法,给具体构件实例新增额外的功能

结构图:

image-20220809170258656

2.模式的实现

//抽象构件角色--汽车
public interface DecoratCompomentCar {

    void showCar();//展示汽车的基本信息

}

//具体构件角色--实现抽象构件角色
public class ConcreteCompomentCar implements DecoratCompomentCar {

    public ConcreteCompomentCar(){
        System.out.println("生产一辆车");
    }

    @Override
    public void showCar() {
        System.out.println("这是一辆刚生产出来的车");
    }

}

//抽象装饰角色--汽车配件
public class AbstractDecoratorParts implements DecoratCompomentCar{

    private DecoratCompomentCar compomentCar;//包含构件实例(车)

    public AbstractDecoratorParts(DecoratCompomentCar compomentCar){
        this.compomentCar = compomentCar;
    }

    @Override
    public void showCar() {
        compomentCar.showCar();
    }
}

//具体装饰者角色-继承抽象装饰角色,便于在该类下对具体构件添加对应的功能
public class ConcreteDecoratorCar extends AbstractDecoratorParts{

    public ConcreteDecoratorCar(DecoratCompomentCar compomentCar) {
        super(compomentCar);
    }

    @Override
    public void showCar() {
        super.showCar();
        carCoating();
        addTail();
    }

    //给车子添加尾翼
    public void addTail(){
        System.out.println("给车子添加一个尾翼");
    }

    //给车子镀膜
    public void carCoating(){
        System.out.println("给车子镀膜");
    }

}

//测试
    @Test
    void decoratorTest(){
        DecoratCompomentCar compomentCar = new ConcreteCompomentCar();//未经装饰的车
        compomentCar.showCar();
        System.out.println("---------------------");
        DecoratCompomentCar decoratorCar = new ConcreteDecoratorCar(compomentCar);//经过装饰后的车
        decoratorCar.showCar();
    }
//打印内容

生产一辆车
这是一辆刚生产出来的车
---------------------
这是一辆刚生产出来的车
给车子镀膜
给车子添加一个尾翼

3.模式的应用场景

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

Tips: 装饰模式在语言中的最著名的应用莫过于Java l/O标准库的设计了。例如,InputStream的子类FilterlnputStream,OutputStream的子类FilterOutputStream,Reader的子类BufferedReader 以及 FilterReader,还有 Writer的子类BufferedWriter、FilterWriter 以及PrintWriter等,它们都是抽象装饰类。

使用装饰模式给文件输入流动态的添加缓存

//text.txt内容  hello  decorator
//测试
    @Test
    void ioTest() throws Exception {
        BufferedReader in = null;
        try {
            in = new BufferedReader(new FileReader("D:\\tools\\test.txt"));
            in.lines().forEach(read-> System.out.println(read));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (null!=in){
                in.close();
            }
        }
    }
//输出
hello
decorator

4.装饰模式的扩展

  • 当具体构件角色只有一个时,可以不要抽象构件角色,直接使用抽象装饰角色继承具体构件角色
  • 当具体装饰角色只有一个时,可以不要抽象装饰角色,将抽象装饰角色和具体装饰角色进行合并,并进行功能的添加

十-外观模式

生活中,我们常常遇到,办理一件事的时候需要去往各个窗口甚至不同部门办理业务(房车过户等),如果此时能有一个综合部门能代理其他窗口和部门的业务,那我们只需要找综合部门即可,大大节约了我们的时间,提升了工作效率。

软件设计也是如此,当随着系统功能越来越多,越来越复杂,客户端的访问将会随之变得越来越复杂。当子系统发生变化时,客户端也要发生变化,此时就违背了“迪米特法则”。此时有必要为多个子系统提供一个统一的的接口,减少系统的耦合度,这就是外观模式的目标。

1.模式的定义与特点

外观模式: 通过为多个复杂的⼦子系统提供一个一致的接口,而使这些⼦子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性

优点:

  • 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。
  • 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。
  • 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程,因为编译一个子系统不会影响其他的子系统,也不会影响外观对象。

缺点:

  • 不能很好地限制客户使用子系统类。
  • 增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”

2.模式的结构和实现

1.外观模式的结构

  • 外观角色: 对多个子系统提供对外访问的统一接口。
  • 子系统角色: 实线系统的部分功能,客户端可以通过外观角色访问。
  • 客户端角色: 通过外观角色访问子系统功能的用户。

结构图

image-20221010103113628

2.外观模式的实现

//外观角色
public class AppearanceRole {
    //系统1
    private SystemRoleOne systemRoleOne = new SystemRoleOne();
    //系统2
    private SystemRoleTwo systemRoleTwo = new SystemRoleTwo();

    //调用系统1和系统2的方法
    public void callMethod() {
        systemRoleOne.showSomething();
        systemRoleTwo.showSomething();
    }
}

//系统角色1
public class SystemRoleOne {

    public void showSomething() {

        System.out.println("走完流程1.。。。。");
    }
}
//系统角色2
public class SystemRoleTwo {

    public void showSomething() {
        System.out.println("走完流程2.。。。。");
    }
}
//客户端角色
public class ClientAppear {

    public static void main(String[] args) {
        AppearanceRole role = new AppearanceRole();
        role.callMethod();
    }
}
//走完流程1.。。。。
//走完流程2.。。。。

3. 外观模式的应用场景

  • 对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。
  • 当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问。
  • 当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。

4.外观模式的扩展

在外观模式中,当增加或移除子系统时需要修改外观类,这违背了“开闭原则”。如果引入抽象外观类,则在一定程度上解决了该问题。

image-20221010103654430

代码实现

//抽象外观角色
abstract class AbstractAppearanceRole {

    public void callMethod() {

    }
}

//外观角色,继承抽象外观,重写callMethod方法
public class AppearanceRoleOne extends AbstractAppearanceRole {

    private SystemRoleOne systemRoleOne = new SystemRoleOne();

    private SystemRoleTwo systemRoleTwo = new SystemRoleTwo();

    @Override
    public void callMethod() {
        systemRoleOne.showSomething();
        systemRoleTwo.showSomething();
    }
}

//系统角色1
public class SystemRoleOne {

    public void showSomething() {

        System.out.println("走完流程1.。。。。");
    }
}
//系统角色2
public class SystemRoleTwo {

    public void showSomething() {
        System.out.println("走完流程2.。。。。");
    }
}

//客户端角色
public class ClientAppear {

    public static void main(String[] args) {
        AbstractAppearanceRole abstractAppearanceRole = new AppearanceRoleOne();
        abstractAppearanceRole.callMethod();
    }
}
正文到此结束