温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java中的装饰模式怎么用

发布时间:2021-07-24 10:50:04 来源:亿速云 阅读:112 作者:chen 栏目:大数据

这篇文章主要介绍“java中的装饰模式怎么用”,在日常操作中,相信很多人在java中的装饰模式怎么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java中的装饰模式怎么用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 模式的定义

如何实现灵活的奖金计算?假设奖金的计算体系如下:

  • 每个人当月业务奖金:当月销售额 * 3%

  • 每个人累计奖金:总的回款额 * 0.1%

  • 团队奖金:团队总销售额 * 1%

奖金计算面临的问题: 
1. 计算逻辑复杂 
2. 要有灵活性,可以方便地增加或者减少功能 
3. 动态组合计算,不同的人参与的计算不同

抽象出来的问题:如何才能透明地给一个对象增加功能,并实现功能的动态组合?

装饰模式的定义: 
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

2. UML图

java中的装饰模式怎么用 
Component:组件对象的接口,可以给这些对象动态地添加职责

ConcreteComponent:具体的组件对象,实现组件接口,通常是被装饰器装饰的原始对象,也就是可以给这个对象添加职责

Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象

ConcreteDecorator:具体的装饰器对象,实现具体要向被装饰对象添加的功能

代码:

/**

 * 在内存中模拟数据库,准备点测试数据,好计算奖金

 */public class TempDB {

    private TempDB(){}    /**

     * 记录每个人的月度销售额,只用了人员,月份没有用

     */

    public static Map<String,Double> mapMonthSaleMoney = new HashMap<String,Double>();    static{        //填充测试数据

        mapMonthSaleMoney.put("张三",10000.0);

        mapMonthSaleMoney.put("李四",20000.0);

        mapMonthSaleMoney.put("王五",30000.0);

    }

}/**

 * 计算奖金的组件接口

 */public abstract class Component {

    /**

     * 计算某人在某段时间内的奖金,有些参数在演示中并不会使用,

     * 但是在实际业务实现上是会用的,为了表示这是个具体的业务方法,

     * 因此这些参数被保留了

     * @param user 被计算奖金的人员

     * @param begin 计算奖金的开始时间

     * @param end 计算奖金的结束时间

     * @return 某人在某段时间内的奖金

     */

    public abstract double calcPrize(String user,Date begin,Date end);

}/**

 * 基本的实现计算奖金的类,也是被装饰器装饰的对象

 */public class ConcreteComponent extends Component{


    public double calcPrize(String user, Date begin, Date end) {        //只是一个默认的实现,默认没有奖金

        return 0;

    }

}/**

 * 装饰器的接口,需要跟被装饰的对象实现同样的接口

 */public abstract class Decorator extends Component{

    /**

     * 持有被装饰的组件对象

     */

    protected Component c;    /**

     * 通过构造方法传入被装饰的对象

     * @param c被装饰的对象

     */

    public Decorator(Component c){        this.c = c;

    }    public double calcPrize(String user, Date begin, Date end) {        //转调组件对象的方法

        return c.calcPrize(user, begin, end);

    }

}/**

 * 装饰器对象,计算当月业务奖金

 */public class MonthPrizeDecorator extends Decorator{

    public MonthPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先获取前面运算出来的奖金

        double money = super.calcPrize(user, begin, end);        //2:然后计算当月业务奖金,按照人员和时间去获取当月的业务额,然后再乘以3%

        double prize = TempDB.mapMonthSaleMoney.get(user) * 0.03;

        System.out.println(user+"当月业务奖金"+prize);        return money + prize;

    }


}/**

 * 装饰器对象,计算累计奖金

 */public class SumPrizeDecorator extends Decorator{

    public SumPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先获取前面运算出来的奖金

        double money = super.calcPrize(user, begin, end);        //2:然后计算累计奖金,其实这里应该按照人员去获取累计的业务额,然后再乘以0.1%

        //简单演示一下,假定大家的累计业务额都是1000000元

        double prize = 1000000 * 0.001;

        System.out.println(user+"累计奖金"+prize);        return money + prize;

    }


}/**

 * 装饰器对象,计算当月团队业务奖金

 */public class GroupPrizeDecorator extends Decorator{

    public GroupPrizeDecorator(Component c){        super(c);

    }    public double calcPrize(String user, Date begin, Date end) {        //1:先获取前面运算出来的奖金

        double money = super.calcPrize(user, begin, end);        //2:然后计算当月团队业务奖金,先计算出团队总的业务额,然后再乘以1%

        //假设都是一个团队的

        double group = 0.0;        for(double d : TempDB.mapMonthSaleMoney.values()){

            group += d;

        }        double prize = group * 0.01;

        System.out.println(user+"当月团队业务奖金"+prize);        return money + prize;

    }


}/**

 * 使用装饰模式的客户端

 */public class Client {

    public static void main(String[] args) {        //先创建计算基本奖金的类,这也是被装饰的对象

        Component c1 = new ConcreteComponent();        //然后对计算的基本奖金进行装饰,这里要组合各个装饰

        //说明,各个装饰者之间最好是不要有先后顺序的限制,也就是先装饰谁和后装饰谁都应该是一样的



        //一层一层叠加的功能

        //先组合普通业务人员的奖金计算

        Decorator d1 = new MonthPrizeDecorator(c1);

        Decorator d2 = new SumPrizeDecorator(d1);   


        //注意:这里只需要使用最后组合好的对象调用业务方法即可,会依次调用回去

        //日期对象都没有用上,所以传null就可以了

        double zs = d2.calcPrize("张三",null,null);       

        System.out.println("==========张三应得奖金:"+zs);        double ls = d2.calcPrize("李四",null,null);

        System.out.println("==========李四应得奖金:"+ls);        //如果是业务经理,还需要一个计算团队的奖金计算

        Decorator d3 = new GroupPrizeDecorator(d2);        double ww = d3.calcPrize("王五",null,null);

        System.out.println("==========王经理应得奖金:"+ww);


    }

}

3. 研磨设计模式

1)装饰模式的功能:实现动态地为对象添加功能,一层一层的包装

2)类功能的扩展:1. 继承 2.对象的组合

3)Java中的装饰模式:IO流 
java中的装饰模式怎么用

  • InputStream相当于Component

  • FileInputStream,ObjectInputStream,StringBufferInputStream相当于ConcreteComponent

  • FilterInputStream相当于Decorator

  • DataInputStream,BufferedInputStream相当于ConcreteDecorator

4)装饰器模式与AOP 
AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点植入到面向对象的软件系统中,从而实现了横切关注点的模块化。 
java中的装饰模式怎么用 
AOP能够将那些与业务无关,却被业务模块所共同调用的逻辑,比如,事务处理,日志管理,权限控制,封装起来,便于减少系统的重复代码,降低模块间的耦合度,利于未来的维护和操作。 
AOP一个更重要的变化是思想上的变化(主从换位),让原本主动调用的功能模块变成了被动等待。

/**

 * 商品销售管理的业务接口  相当于Component

 */public interface GoodsSaleEbi {

    /**

     * 保存销售信息,本来销售数据应该是多条,太麻烦了,为了演示,简单点

     * @param user 操作人员

     * @param customer 客户

     * @param saleModel 销售数据

     * @return 是否保存成功

     */

    public boolean sale(String user,String customer,SaleModel saleModel);

}/**

 * 封装销售单的数据,简单的示意一些

 */public class SaleModel {

    /**

     * 销售的商品

     */

    private String goods;    /**

     * 销售的数量

     */

    private int saleNum;    public String getGoods() {        return goods;

    }    public void setGoods(String goods) {        this.goods = goods;

    }    public int getSaleNum() {        return saleNum;

    }    public void setSaleNum(int saleNum) {        this.saleNum = saleNum;

    }    public String toString(){        return "商品名称="+goods+",购买数量="+saleNum;

    }

}/**

 * 业务对象

 */public class GoodsSaleEbo implements GoodsSaleEbi{


    public boolean sale(String user,String customer, SaleModel saleModel) {

        System.out.println(user+"保存了"+customer+"购买 "+saleModel+" 的销售数据");        return true;

    }

}/**

 * 装饰器的接口,需要跟被装饰的对象实现同样的接口

 */public abstract class Decorator implements GoodsSaleEbi{

    /**

     * 持有被装饰的组件对象

     */

    protected GoodsSaleEbi ebi;    /**

     * 通过构造方法传入被装饰的对象

     * @param ebi被装饰的对象

     */

    public Decorator(GoodsSaleEbi ebi){        this.ebi = ebi;

    }

}/**

 * 实现权限控制

 */public class CheckDecorator extends Decorator{

    public CheckDecorator(GoodsSaleEbi ebi){        super(ebi);

    }    public boolean sale(String user,String customer, SaleModel saleModel) {        //简单点,只让张三执行这个功能

        if(!"张三".equals(user)){

            System.out.println("对不起"+user+",你没有保存销售单的权限");            //就不再调用被装饰对象的功能了

            return false;

        }else{            return this.ebi.sale(user, customer, saleModel);

        }       

    }

}/**

 * 实现日志记录

 */public class LogDecorator extends Decorator{

    public LogDecorator(GoodsSaleEbi ebi){        super(ebi);

    }    public boolean sale(String user,String customer, SaleModel saleModel) {        //执行业务功能

        boolean f = this.ebi.sale(user, customer, saleModel);        //在执行业务功能过后,记录日志

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

        System.out.println("日志记录:"+user+"于"+df.format(new Date())+"时保存了一条销售记录,客户是"+customer+",购买记录是"+saleModel);        return f;

    }


}public class Client {

    public static void main(String[] args) {        //得到业务接口,组合装饰器

        GoodsSaleEbi ebi = new CheckDecorator(new LogDecorator(new GoodsSaleEbo()));        //准备测试数据

        SaleModel saleModel = new SaleModel();

        saleModel.setGoods("Moto手机");

        saleModel.setSaleNum(2);        //调用业务功能

        ebi.sale("张三","张三丰", saleModel);

        ebi.sale("李四","张三丰", saleModel);

    }

}

5)装饰器模式的本质:动态组合

到此,关于“java中的装饰模式怎么用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI