[19/04/27-星期六] GOF23_结构型模式(装饰模式、外观模式)

本文深入探讨了软件设计中的装饰模式和外观模式,详细解释了装饰模式如何动态地为对象添加新功能,以及外观模式如何简化复杂系统的接口。通过实例展示了两种模式的应用场景和优缺点。

一、装饰模式(decorator)

    职责:动态的为一个对象增加新的功能。

    是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,避免类体系的膨胀。

    实现细节:

– Component抽象构件角色:真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。

– ConcreteComponent 具体构件角色(真实对象):IO流中的FileInputStream、FileOutputStream

– Decorator装饰角色:持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象,这样,就能在真实对象调用前后增加新的功能。

– ConcreteDecorator具体装饰角色:负责给构件对象增加新的责任。

【被装饰对象与装饰对象】

/***
 * 抽象组件ICar
 */
package cn.sxt.decorator;

public interface ICar {
    void move();

}

//具体构件对象,被装饰对象,真实对象:普通的汽车
class Car implements ICar{
    public void move() {
        System.out.println("一辆普通的车");        
    }    
}

//装饰组件(们的祖宗),要传进去一个被装饰对象
class SuperCar implements ICar{
    protected ICar car;

    public SuperCar(ICar car) {
        this.car=car;        
    }
    @Override
    public void move() {
        car.move();//调用的是接口中的move方法,因为car是ICar类的对象
    }
}

//各种具体装饰
class FlyCar extends SuperCar{

    public FlyCar(ICar car) {
        super(car);        
    }
    public void fly() {
        System.out.println("天上飞");    
    }

    @Override
    public void move() {
        super.move();//表示调用父类SuperCar的move方法
        fly();
    }
}


class WaterCar extends SuperCar{

    public WaterCar(ICar car) {
        super(car);        
    }
    public void swim() {
        System.out.println("水中潜");    
    }

    @Override
    public void move() {
        super.move();//表示调用父类SuperCar的move方法
        swim();
    }
}

class AICar extends SuperCar{

    public AICar(ICar car) {
        super(car);        
    }
    public void auto() {
        System.out.println("自动驾驶");    
    }

    @Override
    public void move() {
        super.move();//表示调用父类SuperCar的move方法
        auto();
    }
}

【客户端】

/**
 * 
 */
package cn.sxt.decorator;

public class Client {
    public static void main(String[] args) {
        Car car=new Car();//被装饰对象,真实角色
        car.move();
        System.out.println("----增加新的功能:天上飞----");
        FlyCar flyCar=new FlyCar(car);
        flyCar.move();
        System.out.println("----增加新的功能:天上飞+水下潜----");
        WaterCar waterCar=new WaterCar(flyCar);//直接传入一个飞行汽车,在飞行汽车的基础上搞装饰(加水里游)
        waterCar.move();
        System.out.println("----增加新的功能:天上飞+人工智能----");
        AICar iCar=new AICar(new FlyCar(car));//也可以这样写
        iCar.move();
        
    }
}

【UML类图】

示例场景:

– IO中输入流和输出流的设计

– Swing包中图形界面构件功能

– Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper类,增强了request对象的功能。

– Struts2中,request,response,session对象的处理

• 总结:

装饰模式(Decorator)也叫包装器模式(Wrapper)装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类

可以独立变化,以便增加新的具体构建类和具体装饰类。

• 优点:
– 扩展对象功能,比继承灵活,不会导致类个数急剧增加;

– 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象

– 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。
• 缺点:
– 产生很多小对象。大量小对象占据内存,一定程度上影响性能。

– 装饰模式易于出错,调试排查比较麻烦。

与桥接模式的区别:

      两个模式都是为了解决过多子类对象问题。但他们的诱因不一样。桥模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。

      装饰模式是为了增加新的功能。

二、外观模式(facade:正面,外表)

 

【各个政府机构接口】

/***
 * 工商局
 */
package cn.sxt.facade;

public interface AIC {
    void checkName();
}

class HaidianAIC implements AIC{
    public void checkName() {
        System.out.println("在海淀区工商局检查公司名字是否重名!");
        
    }
}

/**
 *银行 
 */
package cn.sxt.facade;

public interface Bank {
    void openAccount();

}

class ICBC implements Bank{
    @Override
    public void openAccount() {
        System.out.println("在中国工商银行开设公司账户!");
        
    }
}

/***
 * 国家质检局
 */
package cn.sxt.facade;

public interface SAMR {
    void orgCode();
}

class HaidianSAMR implements SAMR{
    @Override
    public void orgCode() {
        System.out.println("在海淀区质检局办理组织机构登记代码证!");
        
    }
}


/***
 * 税务局
 */
package cn.sxt.facade;

public interface Tax {
    void taxCertificate();

}

class HaidianTax implements Tax{

    public void taxCertificate() {
        System.out.println("在海淀区税务局办理税务登记!");
        
    }
}

【政府服务大厅】

/***
 *注册公司流程 
 *政府综合办事服务大厅,客户只需要与它打交道即可
 *服务中心去调用各个机构的方法,去与各个机构打交道
 */
package cn.sxt.facade;

public class Register {
    public void registerCompany(){
        AIC aic=new HaidianAIC();
        Bank icbc=new ICBC();
        SAMR samr=new HaidianSAMR();
        Tax tax=new HaidianTax();
        aic.checkName();
        icbc.openAccount();
        samr.orgCode();
        tax.taxCertificate();    
    }
}

 

【客户端】

/***
 * 客户
 */
package cn.sxt.facade;

public class Client {
    public static void main(String[] args) {
        //未采用外观模式的情况,需要一个机构一个机构去跑
    /*    AIC aic=new HaidianAIC();
        Bank icbc=new ICBC();
        SAMR samr=new HaidianSAMR();
        Tax tax=new HaidianTax();
        aic.checkName();
        icbc.openAccount();
        samr.orgCode();
        tax.taxCertificate();*/
        
        //采用外观模式,直接与政府服务中心打交道即可,效果一样
        new Register().registerCompany();// Register re=new Register(); re.registerCompany();
        
    }
}

开发中常见的场景:
频率很高,哪里都会遇到。各种技术和框架中,都有外观模式的使用。如:JDBC封装后的,commons提供的DBUtils类,Hibernate提供的工具类、Spring JDBC工具类等。

                     

 

转载于:https://www.cnblogs.com/ID-qingxin/p/10772093.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值