23种设计模式之结构型设计模式

个人博客: http://zhangsunyucong.top


前言

本篇文章主要讲23种设计模式中的7种结构型设计模式,包括适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式。

适配器模式

适配器模式是将一个类的方法接口转换成客户端期望的接口表示。我们可以约定,把客户端期望的接口叫做目标Targetable,被转换的类叫source。适配器模式可以分为:类的适配器模式,对象的适配器,接口的适配器。

类的适配器模式

已有的被转换的类:

public class SourceClass {

    public void method1() {
        System.out.print("Hi, I am a method in sourceClass");
    }

}

期望的目标:

public interface Targetable {
    void method1();
    void method2();
}

实现目标,进行适配

public class AdapterClass extends SourceClass implements Targetable {

    @Override
    public void method2() {
        System.out.print("Hi All, I am a method in adapterClass");
    }
}

这样子就将SourceClass按照意愿Targetable适配转换成了AdapterClass,AdapterClass具有了SourceClass的所有的功能,同时也达到了扩展SourceClass。由于类的适配器模式是通过继承实现的,它具有了继承的优缺点。关于缺点,比如通过AdapterClass对象可以调用属于SourceClass而在Targetable接口中没有的方法。

对象的适配器模式

对象的适配器模式,就是将原来类的对象转换为目标接口的对象。对象适配器模式没有继承被转换类,而是持有被转换类的对象。这可以避免继承被带来的副作用。

public class AdapterObjectClass implements Targetable{

    private SourceClass mSourceClass;

    public AdapterObjectClass(SourceClass mSourceClass) {
        this.mSourceClass = mSourceClass;
    }

    @Override
    public void method2() {
        System.out.print("hi all, i am a method in AdapterObjectClass");
    }

    @Override
    public void method1() {
        mSourceClass.method1();
    }
}

接口的适配器模式

当一个接口有很多的抽象方法时,当我们写这个接口的实现类,必须实现该接口的全部方法。而有时候接口中并不是所有的抽象方法都是我们必须的,而我们只需要实现其中的某一些方法。为了解决这个问题,我们可以使用接口的适配器模式,引入一个抽象类,这个抽象类提供了接口所有抽象方法的空实现。我们可以继承这个抽象类,并只重写我们需要的方法即可。

比如,在上面我们只要Targetable的method2方法。

public abstract class AdapterInterfaceClass implements Targetable{

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }
}
public class AdapterWraper extends AdapterInterfaceClass {

    @Override
    public void method1() {
        System.out.print("hi all, I am a method in AdapterWraper class");
    }
}

装饰者模式

装饰者模式的核心思想是,装饰者和被装饰者实现同一个接口,将被装饰者注入装饰者中,可以在装饰者中扩展被装饰者。

public interface Person {
    void eat();
}

被装饰者:

public class Man implements Person {

    @Override
    public void eat() {
        System.out.print("There is a man who is eating");
    }
}

装饰者:

public class ManDecorator implements Person {

    private Person mPerson;

    public ManDecorator(Person person) {
        mPerson = person;
    }

    @Override
    public void eat() {
        mPerson.eat();
        drinkWater();
        System.out.print("I finish my lunch");
    }

    private void drinkWater() {
        System.out.print("Man is drinking water");
    }
}

使用:

Man man = new Man();
ManDecorator manDecorator = new ManDecorator(man);
manDecorator.eat();

输出的结果:

There is a man who is eating
Man is drinking water
I finish my lunch

代理模式

注意区别代理模式和动态代理。

生活中代理的例子。比如如果你要租房子,你可能不知道该地区的房子信息,这时你可以找一个熟悉的人来帮忙,这个帮你的人就是代理;又比如,打官司时,我们可能并不精通法律知识,这时我们可以找一个代理律师来帮我们。等等。。对于,代理的工作可以抽象为一个接口。

public interface WorkInterface {
    void rentHouse();
}

一个房东:

public class LandLady implements WorkInterface {

    @Override
    public void rentHouse() {
        System.out.print("您好!我是房东。我这里有房子出租!");
    }
}

代理房东的代理类:

public class Proxy implements WorkInterface {

    private LandLady mLandLady;

    public Proxy() {
        mLandLady = new LandLady();
    }

    @Override
    public void rentHouse() {
        mLandLady.rentHouse();
    }
}

租客去找代理租房子:

WorkInterface proxy = new Proxy();
proxy.rentHouse();

外观模式

在医院里的前台接待员就是一个外观模式的体现。由于病人来到医院可能对医院内部和流程并不熟悉,那么可以由熟悉这些的接待员来帮病人来完成这些事情。

部门1

public class ModuleA {

    //提供给外部调用的方法
    public void a1() {}

    //内部完成工作的实现
    private void a2() {}
    private void a3() {}
}

部门2

public class ModuleB {

    //提供给外部调用的方法
    public void b1() {}

    //内部完成工作的实现
    private void b2() {}
    private void b3() {}
}

部门3

public class ModuleC {

    //提供给外部调用的方法
    public void c1() {}

    //内部完成工作的实现
    private void c2() {}
    private void c3() {}
}

外观类:

public class ModuleFacade {

    private ModuleA mModuleA = new ModuleA();
    private ModuleB mMBModuleB = new ModuleB();
    private ModuleC mMCModuleC = new ModuleC();

    public void a1() {
        mModuleA.a1();
    }

    public void b1() {
        mMBModuleB.b1();
    }

    public void c1() {
        mMCModuleC.c1();
    }

}

当我们需要ModuleA,ModuleB, ModuleC的功能时,我们并不直接和他们打交道,也不需要了解部门的功能是如何实现的,而我们只需要去找外观类沟通即可。

外观模式的关键点是整合。

桥接模式

桥接模式,提供一个解耦或者连接抽象化和实现化的一个桥梁,使得二者可以独立变化。

一个接口作为桥,一个抽象类持有桥。桥和抽象类两者可以独立变化。

桥:

public interface Qiao {
    void toArea();
}

抽象类:

public abstract class FromArea {
    public Qiao qiao;
    abstract public void fromArea();
}

QiaoC.java

public class QiaoC implements Qiao {

    @Override
    public void toArea() {
        System.out.print("I want to go Area C");
    }
}

QiaoD.java

public class QiaoD implements Qiao {

    @Override
    public void toArea() {
        System.out.print("I want to go Area D");
    }
}

FromAreaA.java

public class FromAreaA extends FromArea {

    @Override
    public void fromArea() {
        System.out.print("I come from area A");
    }
}

FromAreaB.java

public class FromAreaB extends FromArea {

    @Override
    public void fromArea() {
        System.out.print("I come from area B");
    }
}

使用:

FromAreaA fromAreaA = new FromAreaA();
QiaoC qiaoC = new QiaoC();
fromAreaA.qiao = qiaoC;

fromAreaA.fromArea();
fromAreaA.qiao.toArea();

QiaoD qiaoD = new QiaoD();
fromAreaA.qiao = qiaoD;

fromAreaA.fromArea();
fromAreaA.qiao.toArea();

从上面可以看出,Qiao和FromArea两者是独立变化的,它们的抽象和实现是分离的。

如果有更多的Qiao和FromArea的实现,只要扩展它们即可。

组合模式

组合模式,又叫“整体-部分设计模式”。它一般用于实现树形结构。

节点

public class TreeNode {

    private String name;
    private TreeNode parent;
    private Vector<TreeNode> children = new Vector<>();

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

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setParent(TreeNode parent) {
        this.parent = parent;
    }

    public TreeNode getParent() {
        return parent;
    }

    public void addChild(TreeNode child) {
        children.add(child);
    }

    public boolean removeChild(TreeNode child) {
        return children.remove(child);
    }

    public Enumeration<TreeNode> getChildren() {
        return children.elements();
    }

}

整体,建立一棵树:

public class Tree {
    TreeNode root = null;

    public Tree(String name) {
        root = new TreeNode(name);
    }

    public static void main(String[] args) {
        Tree tree = new Tree("A");
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");

        nodeB.addChild(nodeC);
        tree.root.addChild(nodeB);
        System.out.println("build the tree finished!");
    }
}

享元模式

享元模式主要是实现对象的共享。联想数据库的连接池。

public class ConnectionPool {  
      
    private Vector<Connection> pool;  
      
    /*公有属性*/  
    private String url = "jdbc:mysql://localhost:3306/test";  
    private String username = "root";  
    private String password = "root";  
    private String driverClassName = "com.mysql.jdbc.Driver";  
  
    private int poolSize = 100;  
    private static ConnectionPool instance = null;  
    Connection conn = null;  
  
    /*构造方法,做一些初始化工作*/  
    private ConnectionPool() {  
        pool = new Vector<Connection>(poolSize);  
  
        for (int i = 0; i < poolSize; i++) {  
            try {  
                Class.forName(driverClassName);  
                conn = DriverManager.getConnection(url, username, password);  
                pool.add(conn);  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
  
    /* 返回连接到连接池 */  
    public synchronized void release() {  
        pool.add(conn);  
    }  
  
    /* 返回连接池中的一个数据库连接 */  
    public synchronized Connection getConnection() {  
        if (pool.size() > 0) {  
            Connection conn = pool.get(0);  
            pool.remove(conn);  
            return conn;  
        } else {  
            return null;  
        }  
    }  
}  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容

  • 原文链接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤独杂货铺阅读 1,479评论 0 3
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,820评论 1 15
  • 乐小姐大学毕业了,那一天她的男神秋先生在朋友圈里的小视频里唱歌,还是那首《思念是一种病》。 秋先...
    荒野里的牧人阅读 252评论 0 1
  • 今天下午,从北京回来的路上,坐在火车上,翻看微信群里的聊天记录,看到猫爷在剽悍江湖的群里说到2017年第一季度的进...
    梅洛的听雨轩阅读 237评论 5 4
  • 今天早上吃完早饭, 爸爸送我去上学。今天要考试, 我只带了文具盒和科学一课一练,科学一课一练 是用来垫着做试卷儿的...
    轩小豆阅读 286评论 0 1