设计模式9,享元模式、组合模式、桥接模式

本文介绍了三种设计模式——享元模式、组合模式和桥接模式。享元模式通过共享技术减少对象数量,提高系统效率;组合模式用于表示对象的层次结构,使客户端对单个对象和组合对象处理方式一致;桥接模式则旨在分离抽象部分与其具体实现,增加系统的灵活性。每种模式都有其适用场景、优缺点和实际应用案例。
摘要由CSDN通过智能技术生成

目录

享元模式

组合模式

桥接模式


享元模式

提供了减少对象数量从而改善应用所需的对象结构的方式。运用共享技术有效的支持大量细粒度的对象。简单说就是减少创建对象的数量,减少内存的占用,提高性能。

类型:结构型

使用场景:常用于系统底层开发,以解决系统的性能问题。系统有大量相似对象,需要缓冲池的场景。

优点:减少对象创建,降低内存中对象的数量,降低系统的内存,提高效率。减少内存之外其他资源的占用。

缺点:需要关注内部外部的状态,关注线程安全问题。使系统、程序的逻辑复杂化(使用享元对象还要分离出内部外部状态,外部状态不应随着内部状态变化而变化,否则系统就会分乱了。)

补充概念:

内部状态:在享元对象内部,不会随着环境改变而改变的部分。

外部状态:会随着环境改变而改变,是不可以共享的状态。

例子:

public interface Game {
    void play();
}
public class Player implements Game {
    private String username;
    private String code;
    private String role = "玩家";

    public Player(String username) {
        this.username = username;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public void play() {
        System.out.println(role + username + "玩游戏");
    }
}
public class PlayerManager {
    private static final Map<String , Player> PLAYER_MAP = new HashMap<>();

    public static Player getPlayer(String username){
        Player player = PLAYER_MAP.get(username);
        if(player == null){
            System.out.println("创建账号:" + username);
            player = new Player(username);
            String code = "code" + PLAYER_MAP.size();
            player.setCode(code);
            PLAYER_MAP.put(username , player);
        }
        return player;
    }
}
public class Test {
    private static final String players[] = {"haozi","rou","mark","michael","clark"};

    public static void main(String[] args) {
        for (int i = 0 ; i < 10 ; i ++){
            String username = players[(int)(Math.random() * players.length)];
            Player player1 = PlayerManager.getPlayer(username);
            player1.play();
        }
    }
}

 类图

PlayerManager来创建和管理Player,Player实现Game接口,player中,role就属于内部状态,其他两个属于外部状态。

 用到设计模式的源码:

Integer#valueOf


组合模式

将对象组成树形结构以表示“整体-部分”的层次结构。使客户端对单个对象和组合对象保持一致的处理方式。简单地说就是把多个对象组合成一个对象,简化对多个对象的访问。

类型:结构型

使用场景:希望客户端可以忽略组合对象和单个对象的差异时。处理一个树形结构时。

优点:可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次。让客户端忽略层次的差异,方便对整个层次结构进行控制。简化客户端代码。符合开闭原则。

缺点:限制类型时会比较复杂。使设计变得更加抽象。

例子:

public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void remove(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持删除操作");
    }

    public String getName(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取名称操作");
    }

    public Double getPrice(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取价格操作");
    }

    public void print(){
        throw new UnsupportedOperationException("不支持打印操作");
    }
}
public class Course extends CatalogComponent {
    private String name;
    private Double price;

    public Course(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public Double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("打印:" + name + "价格:" + price);
    }
}
public class CourseCatalog extends CatalogComponent {
    private String name;
    private List<CatalogComponent> list = new ArrayList<>();

    public CourseCatalog(String name) {
        this.name = name;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        list.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        list.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for (CatalogComponent catalogComponent : list){
            System.out.print("  ");
            catalogComponent.print();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("linux课程" , 10.00);

        CatalogComponent javaCatalog = new CourseCatalog("java课程目录");
        CatalogComponent javaCourse1 = new Course("springboot源码分析" , 80.00);
        CatalogComponent javaCourse2 = new Course("设计模式" , 50.00);

        javaCatalog.add(javaCourse1);
        javaCatalog.add(javaCourse2);

        CatalogComponent mainCatalog = new CourseCatalog("主目录");

        mainCatalog.add(linuxCourse);
        mainCatalog.add(javaCatalog);

        mainCatalog.print();
    }
}

类图:

从图中就可以清晰地看出从属关系,从代码也可以看出树形结构,目录和课程都实现同一个接口,根据不同的情况重写响应的方法。结果:

如果打印主目录,现有代码是这个结果,那如果我还想把三级目录再缩进两格,让层次更清晰,就需要在目录类中加很多逻辑代码进行实现,这里用简单的加个level字段举例实现。

public class CourseCatalog extends CatalogComponent {
    private String name;
    private List<CatalogComponent> list = new ArrayList<>();
    private Integer level;

    public CourseCatalog(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        list.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        list.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for (CatalogComponent catalogComponent : list){
            if (this.level != null){
                for (int i = 0 ; i < this.level ; i ++){
                    System.out.print("  ");
                }
            }
            catalogComponent.print();
        }
    }
}

运行结果:

所以组合模式的缺点也就在此了。

用到设计模式的源码:

Container这个类首先继承了Component,后面在add的时候,增加自己的父类

在addImpl中,也有很多层级判断

 再看MixedSqlNode

很典型的组合模式,挑两个类图看看


桥接模式

 使抽象部分与它的具体实现分离,是他们都可以独立的变化,实现一定的解耦。通过组合的方式建立两个类之间的联系,而不是继承。

类型:结构型

使用场景:抽象和具体实现之间增加更多的灵活性。一个类存在多个独立的变化维度,并且这些维度都需要独立的进行扩展。不希望使用继承,或因为多层继承导致系统类的个数剧增。

优点:分离抽象部分及其具体实现部分。提高了系统的可扩展性。符合开闭原则,合成复用原则。

缺点:增加了系统的理解和设计难度(因为类之间的关系建立在抽象层,所以一开始就要面对抽象层进行设计和编码)。需要正确的识别出系统中两个独立变化的维度。

例子:

public interface Account {
    Account openAccount();
    void showAccountType();
}
public class DepositAccount implements Account{
    @Override
    public Account openAccount() {
        System.out.println("打开定期账号");
        return new DepositAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是定期账号");
    }
}
public class SavingAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开活期账号");
        return new SavingAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是活期账号");
    }
}
public abstract class Bank {
    protected Account account;
    public Bank(Account account){
        this.account = account;
    }
    abstract Account openAccount();
}
public class ABCBank extends Bank {
    public ABCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开农业银行账号");
        return account;
    }
}
public class ICBCBank extends Bank {
    public ICBCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开工商银行账号");
        return account;
    }
}
public class Test {
    public static void main(String[] args) {
        Bank icbcBank1 = new ICBCBank(new DepositAccount());
        Account icbcAccount1 = icbcBank1.openAccount();
        icbcAccount1.showAccountType();

        Bank abcBank1 = new ICBCBank(new SavingAccount());
        Account abcAccount1 = abcBank1.openAccount();
        abcAccount1.showAccountType();

        Bank icbcBank2 = new ICBCBank(new SavingAccount());
        Account icbcAccount2 = icbcBank2.openAccount();
        icbcAccount2.showAccountType();

        Bank abcBank2 = new ICBCBank(new DepositAccount());
        Account abcAccount2 = abcBank2.openAccount();
        abcAccount2.showAccountType();
    }
}

类图:

银行是各自的实现,账号也是各自的实现,这样,就可以各种排列组合,各自扩展自己的银行或账号都不会被影响。

运行结果

这里有个伏笔,运行结果不是非常对:

银行类的openAccount不要自己实现接口,把行为委托给抽象父类注入的Account,这样Account怎么变,这里都不变。

用到设计模式的源码:

java.sql.DriverManager

 其中DriverInfo就是对于Driver的封装

 接下来看看Driver的实现类

看下mysql的Driver

 调用DriverManager的registerDriver完成驱动注册。再看getConnection,用来获取数据库连接

获取完以后返回Connection,Connection接口提供了对数据库操作的各种方法。

所以可以想象成,Driver和DriverManager实现了桥接,Driver接口可以实现各种数据库驱动,DriverManager通过驱动获取连接,并且提供数据库的操作方法,不同的厂商有不同的驱动,实现各自数据库操作的方法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值