设计模式->结构型模式->装饰者模式

来源:互联网 发布:c语言游戏程序代码 编辑:程序博客网 时间:2024/06/06 10:55

1.定义:动态的给一个对象添加一些额外的职责,就增加功能来说该模式比生成子类更加灵活。类型的继承 > 行为的继承。eg:I/O流采用的就是该模式

2.UML:


3.涉及角色

        抽象组件角色:一般为抽象类或者接口主要定义了最原始最核心的行为

        具体组件角色:抽象组件行为的具体实现,该实现也是最原始最核心的,其实可以理解为最基本的行为。该角色也是后续需要装饰的对象即被装饰者。该角色也可以有自己的行为

抽象装饰者:继承抽象组件,同时持有抽象组件的实例。从外类扩展抽象组件

具体装饰者:装饰被装饰者,也就是说在此处我们动态的给对象添加了额外的职责。即除了核心职责外还有我们自己细化的职责

4.优点

1.装饰类和被装饰不耦合,相互独立,可以独自扩充。因为装饰者依赖的是抽象组件。抽象组件无需知道装饰者类,因为装饰者采用的是外部类的方式来扩展功能,装饰者也无需知道具体组件,

2.可以动态的添加职责

3.有效的将核心功能和装饰功能分开,同时也去除相关类中重复的装饰逻辑

        4.作为继承的替换方案,该模式可以减少明显减少子类个数,装饰顺序不同导致的行为也不同,也就是说装饰过程不固定

5.缺点

1.多层装饰会增加系统的复杂性

6.使用场景

        1.剥离核心业务和装饰功能。即在代码重构的过程中可以剥离核心业务和装饰功能

2.动态的添加职责,增强现有行为

3.需要执行特殊行为时客户端可以根据需要有选择,有顺序的包装现有对象

7.Code

//抽象组件

//抽象组件public interface IUserService {    //核心方法:将数据插入到DB中。只负责数据的插入不负责数据的校验/过滤/加密    public void insertDataToDB(User user);    //TODO 其他行为}
//具体组件即被装饰者

//具体组件,可以在具体组件中添加行为以及属性public class UserService implements IUserService {    //TODO 具体组件可以含有自己的行为以及属性    @Override    public void insertDataToDB(User user) {        //TODO 添加具体组件行为        System.out.println("insert User:" + user.toString());        //TODO 添加具体组件行为    }}
//抽象装饰者

//装饰者,继承抽象组件并且持有抽象组件的实例,类型继承多余行为继承,从外类扩展//该类中也可以定义行为和属性public class Decorate implements IUserService {    //TODO 定义行为和属性    private IUserService userService;    public Decorate(IUserService userService) {        this.userService = userService;    }    @Override    public void insertDataToDB(User user) {        this.userService.insertDataToDB(user);    }}
具体装饰者

//具体装饰者public class CheckoutData extends Decorate {    public CheckoutData(IUserService userService) {        super(userService);    }    @Override    public void insertDataToDB(User user) {        //先校验数据后在插入        if(this.checkoutUserName(user) && this.checkoutUserSex(user)) {            super.insertDataToDB(user);            return;        }        System.out.println("校验失败");    }    private boolean checkoutUserName(User user) {        //TODO 添加业务逻辑        System.out.println("校验用户名");        return null != user.getName() || user.getName().trim().length() != 0;    }    private boolean checkoutUserSex(User user) {        //TODO 添加业务逻辑        System.out.println("校验用户性别");        return null != user.getSex() || user.getSex().trim().length() != 0;    }}//具体装饰者public class FilterData extends Decorate {    public FilterData(IUserService userService) {        super(userService);    }    @Override    public void insertDataToDB(User user) {        filterData(user);        super.insertDataToDB(user);    }    private void filterData(User user) {        if(user.getName().contains("a")) {            user.setName(user.getName().replaceAll("a", "*"));        }        System.out.println("过滤后数据:" + user.toString());    }}public class EncodeData extends Decorate {    public EncodeData(IUserService userService) {        super(userService);    }    @Override    public void insertDataToDB(User user) {        encodeUser(user);        super.insertDataToDB(user);    }    private void encodeUser(User user) {        System.out.println("加密:" + user.getName().replaceAll(user.getName(), "*"));    }}
实体类

public class User {    private long id;    private String name;    private String sex;    public User(long id, String name, String sex) {        this.id = id;        this.name = name;        this.sex = sex;    }    public User() {    }    public long getId() {        return id;    }    public void setId(long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getSex() {        return sex;    }    public void setSex(String sex) {        this.sex = sex;    }    @Override    public String toString() {        return "name:" + this.name + ", sex:" + this.sex;    }}


客户端

public class Client {    public static void main(String[] args) {        User user = new User(1l,"Bana", "man");        IUserService us = new UserService();        Decorate decorate3 = new EncodeData(us);        Decorate decorate2 = new FilterData(decorate3);        Decorate decorate1 = new CheckoutData(decorate2);        decorate1.insertDataToDB(user);//客户端可以根据实际需要动态组织装饰顺序以及装饰层次以达到在特殊场景下的使用    }}