zoukankan      html  css  js  c++  java
  • 设计模式(7)之装饰模式

    1. 什么是装饰模式
      装饰( Decorator )模式又叫做包装模式。通过一种对client透明的方式来扩展对象的功能,是继承关系的一个替换方案。

    2. 装饰模式的结构
      这里写图片描写叙述

    3. 装饰模式的角色和职责

      抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口。
      详细组件角色:为抽象组件的实现类。
      抽象装饰角色:包括一个组件的引用。并定义了与抽象组件一致的接口。
      详细装饰角色:为抽象装饰角色的实现类。负责详细的装饰。

    以一个样例来解释一下,假设我们如今要想造一辆车,对 ! 就是车, Car。

    大家都知道,不同的车功能不同,有的车能够跑,废话!

    有的车能够飞,有的车能够游泳,有的车能够跳跃。

    。。

    别激动,我就举个样例。

    依照传统的面向对象的思想,我们肯定先定义一个Car的父类,在这个父类中定义一些全部车都具有的功能,比方run(),然后再派生出各种子类继承这个Car父类,然后在子类中再实现自己独特的功能。比如。我声明一个FlyCar继承自Car,然后在FlyCar中实现父类的run()。在实现自己独特的fly()方法。

    你是不是这么想的。别不承认。一般人都是酱紫想的。我也是这么想的,起初我还非常自豪。由于我用到了面向对象的思想!!!

    可是,假设如今我想造一个既能游泳又能飞的车怎么办?难道我定义一个FlySwimCar继承自Car,OK,当然能够。

    可是,随着科技的发展。车的功能越来越丰富,你难道要不停的定义各种组合功能的车吗。你应该知道排列组合吧~~~这显然不符合程序猿偷懒的个性。

    所以。就有了 装饰模式。我们边看代码,边解释。

    首先。定义一个Car基类,当然,这个必须是接口,你懂的。你不可能直接new 一个Car出来吧。谁知道这个Car是具有哪个功能的Car。可是这个接口Car中应该包括最主要的车的功能。

    //Car.java
    public interface Car {
        public void run();
        // 显示车的功能
        public void show();
    }

    最普通的车只是于实现这个接口了,这个车除了能跑之外,啥都不能干。

    对,这就是传说中的 【跑车】。

    //RunCar.java
    
    public class RunCar implements Car{
    
        @Override
        public void run() {
            System.out.println("run...");
        }
    
        @Override
        public void show() {
            this.run();
        }
    
    }

    然后,我想造一辆能Fly的车。怎么办?

    我们先定义一个抽象类CarDecorator。这个类干嘛的呢?就是对车进行包装。为啥是抽象的呢?由于你造一个能Fly的车和造一个能Swim的车,用的材料啥的肯定都不同吧,也就是说包装的内容都不同吧,所以,这个CarDecorator中定义的是包装类共同拥有操作。就好比。把一辆普通的车改造之前,不论你是改装成能Fly的车还是能Swim的车。你首先是不是获得这个普通的车,获得普通车这个操作就是在CarDecorator基类中定义的。

    //CarDecorator.java
    public abstract class CarDecorator {
        private Car car;
    
        public CarDecorator(Car car) {
            this.car = car;
        }
        //提供方法获取包装之前的Car
        //为什么要获取包装之前的Car。废话。不获得之前的Car。你怎么加入新的功能?
        //那么加入功能的方法在哪?我怎么没瞅见。别急呀,往下看,肯定是特定的装饰者加入特定的功能呀。

    public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } //为了显示车具有的功能。定以了这个show()方法 public abstract void show(); }

    好了,如今我们就能够造能飞的车了。

    //FlyCarDecorator.java
    
    public class FlyCarDecorator extends CarDecorator {
    
        public FlyCarDecorator(Car car) {
            super(car);
        }
    
        @Override
        //显示车的功能
        public void show() {
            //先显示原始车的功能,这下知道为啥在CarDecorator中获得改造之前的车了吧。

    this.getCar().show(); this.fly();//加入新的功能 } public void fly(){ System.out.println("fly..."); } }

    同理,我们能够造一个能Swim的车子。

    //SwimCarDecorator.java
    
    public class SwimCarDecorator extends CarDecorator{
    
        public SwimCarDecorator(Car car) {
            super(car);
        }
    
        @Override
        public void show() {
            this.getCar().show();
            this.swim();
        }
    
        public void swim(){
            System.out.println("swim...");
        }
    }
    

    酱紫的话。主函数就会变得非常清爽。

    //MainClass.java
    public class MainClass {
    
        public static void main(String[] args) {
    
            Car car = new RunCar();
            car.show();
    
            System.out.println("--------------------");
    
            SwimCarDecorator swimCar = new SwimCarDecorator(car);
            swimCar.show();
    
            System.out.println("--------------------");
            FlyCarDecorator flyCar = new FlyCarDecorator(car);
            flyCar.show();
    
            System.out.println("--------------------");
    
        }
    }

    执行结果:

    run...
    --------------------
    run...
    swim...
    --------------------
    run...
    fly...
    --------------------
    

    呵呵呵,是不是非常清爽。

    可是你有木有发现一个问题,你说造一个能Fly能Swim的车,如今却仅仅造了一个能run和Siwm。能run和Fly的车,还要不要脸了。

    各位看官,别激动。!

    立即造。立即造。

    正常人的思维是不是酱紫的,我有一个car,仅仅能run。跑车嘛!!

    !如今改造(装饰)一下,能游泳了,然后我希望既能游泳也能飞。怎么办?废话,当然是把能游泳的车加一个翅膀啥的。

    是不是?嗯,这次你想对了。我也是怎么想的。

    如今我们改我们的main函数:

    //MainClass.java
    
    public class MainClass {
    
        public static void main(String[] args) {
    
            Car car = new RunCar();
            car.show();
    
            System.out.println("--------------------");
            //1
            Car swimCar = new SwimCarDecorator(car);
            swimCar.show();
    
            System.out.println("--------------------");
            //2                                3   
            Car flyCar = new FlyCarDecorator(swimCar);
            flyCar.show();
    
            System.out.println("--------------------");
    
        }
    }

    改了三处,和原来的main函数比較下,看见没有。

    为什么这么改,你们不都是怎么想的吗???忘了?往上看看。

    为了适应main函数这么改,我们改动其它的文件呢。我们看一下:

    Car flyCar = new FlyCarDecorator(swimCar);

    原来FlyCarDecorator的构造方法中传递的是Car。你如今传递的是swimCar。swimCar在没改之前是啥类型来着。对。是SwimCarDecorator类型。

    辣么,你如今知道怎么改了吧。

    我们让CarDecorator实现Car接口不就完了吗?
    这里写图片描写叙述

    然后分别在FlyDecorator中实现Car中没有实现的run方法
    这里写图片描写叙述

    这里写图片描写叙述

    好了,代码应该不报错了吧。。。

    如今看下执行结果:

    这里写图片描写叙述
    怎么样,我没食言吧。说给你造个能fly能swim的就给你造了。关键代码写得还是辣么的优雅!

    !嘿嘿嘿,代码不是我写的,我仅仅是分析下。

    可是,有人可能会问,你说改这就改这,说改那就改那,究竟改的合不合理呢?唉,你别说,这么一改。比之前还真的合理。

    首先,是main方法中的调用逻辑,之前已经说过了,这肯定是符合大多人的思考习惯的。

    然后,我们看下CarDecorator实现Car接口合不合理,我们看他的子类FlyDecorator,他继承自CarDecorator,CarDecorator实现了Car接口。所以,FlyDecorator要实现Car中的接口,Car中有两个方法一个是show()和run()。show()方法在CarDecorator中已经定义为抽象方法了,已经被FlyDecorator实现了,如今就剩下run()方法没有实现了。所以,FlyDecorator要实现run()方法。你想想,FlyDecorator实现run方法合理吗???我认为非常合理。你给车装个翅膀让他飞。他就不能跑了?也许人家跑的更快了呢。也许人家跑的姿势更优雅了呢?所以你也得给FlyDecorator改造车的同一时候改动原有功能的机会,是不是?所以我认为非常合理。

    同理,SwimCarsDecorator中的也要实现Car接口中的run()方法。

  • 相关阅读:
    treeview 的动态的绑定
    数据库组件
    webconfig,form验证存角色
    treeView
    web.config 的读写与配置
    .net 开发精华
    asp.net
    在ASP.NET中实现AJAX
    验证js
    用js将form表单同时提交到两个不同页面的方法
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7242881.html
Copyright © 2011-2022 走看看