Java设计模式系列(二):外观模式&装饰器模式

本文介绍了软件设计中的外观模式和装饰器模式。通过家庭影院系统案例,展示如何使用外观模式简化复杂系统的操作流程;并通过咖啡调料问题,阐述装饰器模式在动态扩展对象功能方面的优势。

外观模式(Facade)-6

也叫门面模式,过程模式。

外观模式为子系统中的一组接口提供一致的界面,此模式定义一个高层接口,使得子系统更容易使用。

需求分析

一个家庭影院使用过程:

放下屏幕
开爆米花
开DVD
...
播放DVD
暂停DVD
...
收起屏幕
收起爆米花
关DVD	

使用外观模式,提供高层接口,简化家庭影院操作。

类图关系:

在这里插入图片描述

代码

Client

public class Client {
    public static void main(String[] args) {
        HomeTheatreFacade homeTheatreFacade = new HomeTheatreFacade();
        System.out.println("--ready--");
        homeTheatreFacade.read();
        System.out.println("--play--");
        homeTheatreFacade.play();
        System.out.println("--pause--");
        homeTheatreFacade.pause();
        System.out.println("--end--");
        homeTheatreFacade.end();
    }
}

HomeTheatreFacade

public class HomeTheatreFacade {
    // 子系统
    private DVDPlayer dvdPlayer;
    private Popcorn popcorn;
    private Screen screen;

    // 初始化子系统
    public HomeTheatreFacade() {
        // 结合单例模式
        this.dvdPlayer = DVDPlayer.getInstance();
        this.popcorn = Popcorn.getInstance();
        this.screen = Screen.getInstance();
    }

    // 四个操作步骤

    public void read(){
        screen.down();
        popcorn.open();
        dvdPlayer.on();
    }
    public void play(){
        dvdPlayer.play();
    }
    public void pause(){
        dvdPlayer.pause();
    }
    public void end(){
        dvdPlayer.off();
        popcorn.close();
        screen.up();
    }
}

DVDPlayer

public class DVDPlayer {
    // 单例模式

    private DVDPlayer() {
    }
    private static DVDPlayer instance = new DVDPlayer();

    public static DVDPlayer getInstance() {
        return instance;
    }

    public void on(){
        System.out.println("开DVD");
    }
    public void play(){
        System.out.println("播放DVD");
    }
    public void pause(){
        System.out.println("暂停DVD");
    }
    public void off(){
        System.out.println("关闭DVD");
    }
}

Popcorn

public class Popcorn {
    // 单例模式

    private Popcorn() {
    }
    private static Popcorn instance = new Popcorn();

    public static Popcorn getInstance() {
        return instance;
    }

    public void open(){
        System.out.println("开爆米花");
    }
    public void close(){
        System.out.println("收起爆米花");
    }
}

Screen

public class Screen {
    // 单例模式

    private Screen() {
    }
    private static Screen instance = new Screen();

    public static Screen getInstance() {
        return instance;
    }

    public void down(){
        System.out.println("放下屏幕");
    }
    public void up(){
        System.out.println("收起屏幕");
    }
}

举例

slf4j就是门面,它对多种日志框架进行兼容

slf4j-log4j12就是适配器,它适配log4j这种日志

统一接口调用

Logger logger = LoggerFactory.getLogger(HelloServlet.class);

装饰器模式(Decorator )-7

装饰器模式:动态将新功能附加到对象上。在对象扩展方面,比继承更有弹性,装饰者模式也体现了开闭原则(ocp)

问题引入:咖啡+调料问题。增加单品时,由于搭配种类很多,类的数量会暴增,出现类爆炸。考虑使用装饰者模式。

案例:咖啡调料

Component主体:Drink

ConcreteComponent:各单品咖啡

Decorator:各调料

在这里插入图片描述

CoffeeBar

/**
 * 咖啡点单
 */
public class CoffeeBar {
    public static void main(String[] args) {
        // 1、一杯美式
        Drink order = new LongBlack();
        System.out.println("当前组合价格:"+ order.cost());

        // 2、加一份牛奶
        order = new Milk(order);
        System.out.println("当前组合价格:"+ order.cost());

        // 3、加两份巧克力
        order = new Chocolate(order);
        System.out.println("当前组合价格:"+ order.cost());
        order = new Chocolate(order);
        System.out.println("当前组合价格:"+ order.cost());
    }
}

Drink

/**
 * 饮品抽象类
 */
@Data
public abstract class Drink {
    private float price = 0.0f;
    private String description;

    /**
     * 计算费用
     */
    public abstract float cost();
}

Coffee

/**
 * 被装饰者:咖啡类
 */
public class Coffee extends Drink {
    @Override
    public float cost() {
        // 实现Coffee计算逻辑,如基础价格...
        return super.getPrice();
    }
}

Decorator

/**
 * 装饰器:加调料
 */
public class Decorator extends Drink{
    // 被装饰对象:饮料
    private Drink obj;

    public Decorator(Drink obj) {
        this.obj = obj;
    }

    @Override
    public float cost() {
        // getPrice : 调料的价格
        return super.getPrice() + obj.cost();
    }
}

DeCaf

public class DeCaf extends Coffee {
    public DeCaf(){
        setDescription("无因咖啡");
        setPrice(1.0f);
    }
}

LongBlack

public class LongBlack extends Coffee{
    public LongBlack(){
        setDescription("美式咖啡");
        setPrice(5.0f);
    }
}

Milk

public class Milk extends Decorator {
    public Milk(Drink obj) {
        super(obj);
        setDescription("牛奶");
        setPrice(2.0f);
    }
}

Soy

public class Soy extends Decorator {
    public Soy(Drink obj) {
        super(obj);
        setDescription("豆浆");
        setPrice(1.5f);
    }
}

JDK源码解析:InputStream装饰者模式

public class DecoratorDemo {
    public static void main(String[] args) throws IOException {
        /**
         * 1、InputStream --> Drink抽象类
         * 2、DataInputStream --> Milk装饰者
         * 3、FileInputStream --> LongBlack被装饰者
         */
        InputStream inputStream = new DataInputStream(new FileInputStream("C:\\Users\\hhdww\\Desktop\\abc.txt"));
        System.out.println(inputStream.read());
        inputStream.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值