总体来说设计模式分为三大类:创建型模式、结构型模式和行为型模式。

博主的上一篇文章已经提到过创建型模式,此外该文章还有设计模式概况和设计模式的六大原则。设计模式的六大原则是设计模式的核心思想,详情请看博主的另外一篇文章: Java经典设计模式之五大创建模式(附实例和详解)。

接下来我们看看结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中适配器模式主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。其中的对象的适配器模式是各种结构型模式的起源。

一、适配器模式

适配器模式主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。有点抽象,我们来看看详细的内容。

1.1、类的适配器模式

类的适配器模式核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里。

1
2
3
4
5
6
7
package com.model.structure;
public class Source {
    public void method1() { 
        System.out.println("this is original method!"); 
    
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public interface Targetable {
    /* 与原类中的方法相同 */
    public void method1();
    /* 新类的方法 */
    public void method2();
}

1
2
3
4
5
6
7
package com.model.structure;
public class Adapter extends Source implements Targetable {
    public void method2() {
        System.out.println("this is the targetable method!");
    }
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class AdapterTest {
    public static void main(String[] args) {
        Targetable target = new Adapter();
        target.method1();
        target.method2();
    }
}

AdapterTest的运行结果:

1.2、对象的适配器模式

对象的适配器模式的基本思路和类的适配器模式相同,只是将Adapter类作修改成Wrapper,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.model.structure;
public class Wrapper implements Targetable {
    private Source source;
    public Wrapper(Source source) {
        super();
        this.source = source;
    }
    @Override
    public void method2() {
        System.out.println("this is the targetable method!");
    }
    @Override
    public void method1() {
        source.method1();
    }
}

1
2
3
4
5
6
7
8
9
10
package com.model.structure;
public class AdapterTest {
    public static void main(String[] args) {
        Source source = new Source();
        Targetable target = new Wrapper(source);
        target.method1();
        target.method2();
    }
}

运行结果跟类的适配器模式例子的一样。

1.3、接口的适配器模式

接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行了。

这里看文字描述已经试够清楚的了,因此就不贴代码实例了。

二、装饰模式

装饰模式:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

装饰模式的特点:

(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。继承不能做到这一点,继承的功能是静态的,不能动态增删。

具体看看代码实例

1
2
3
4
5
package com.model.structure;
public interface Sourceable {
    public void method();
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("the original method!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.model.structure;
public class Decorator implements Sourceable {
    private Sourceable source;
    public Decorator(Sourceable source) {
        super();
        this.source = source;
    }
    @Override
    public void method() {
        System.out.println("before decorator!");
        source.method();
        System.out.println("after decorator!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.model.structure;
public class DecoratorTest {
    public static void main(String[] args) {
        //(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
        //(2) 装饰对象包含一个真实对象的引用(reference)
        //(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
        //(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。
        //    在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
        //    继承不能做到这一点,继承的功能是静态的,不能动态增删。
        Sourceable source = new Source();
        Sourceable obj = new Decorator(source);
        obj.method();
    }
}

运行结果:

1
2
3
before decorator!
the original method!
after decorator!

三、代理模式

代理模式就是多一个代理类出来,替原对象进行一些操作。代理类就像中介,它比我们掌握着更多的信息。

具体看看代码实例。

1
2
3
4
5
package com.model.structure;
public interface Sourceable {
    public void method();
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("the original method!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.model.structure;
public class Proxy implements Sourceable {
    private Source source;
    public Proxy() {
        super();
        this.source = new Source();
    }
    @Override
    public void method() {
        before();
        source.method();
        atfer();
    }
    private void atfer() {
        System.out.println("after proxy!");
    }
    private void before() {
        System.out.println("before proxy!");
    }
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class ProxyTest {
    public static void main(String[] args) {
        Sourceable source = new Proxy();
        source.method();
    }
}

运行结果:

1
2
3
before proxy!
the original method!
after proxy!

四、外观模式

外观模式是为了解决类与类之间的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口。

我们以一个计算机的启动过程为例,看看如下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
package com.model.structure;
public class CPU {
    public void startup() {
        System.out.println("cpu startup!");
    }
    public void shutdown() {
        System.out.println("cpu shutdown!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
package com.model.structure;
public class Disk {
    public void startup() {
        System.out.println("disk startup!");
    }
    public void shutdown() {
        System.out.println("disk shutdown!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
package com.model.structure;
public class Memory {
    public void startup() {
        System.out.println("memory startup!");
    }
    public void shutdown() {
        System.out.println("memory shutdown!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.model.structure;
public class Computer {
    private CPU cpu;
    private Memory memory;
    private Disk disk;
    public Computer() {
        cpu = new CPU();
        memory = new Memory();
        disk = new Disk();
    }
    public void startup() {
        System.out.println("start the computer!");
        cpu.startup();
        memory.startup();
        disk.startup();
        System.out.println("start computer finished!");
    }
    public void shutdown() {
        System.out.println("begin to close the computer!");
        cpu.shutdown();
        memory.shutdown();
        disk.shutdown();
        System.out.println("computer closed!");
    }
}

1
2
3
4
5
6
7
8
9
10
package com.model.structure;
public class User {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.startup();
        computer.shutdown();
    }
}

运行结果:

1
2
3
4
5
6
7
8
9
10
start the computer!
cpu startup!
memory startup!
disk startup!
start computer finished!
begin to close the computer!
cpu shutdown!
memory shutdown!
disk shutdown!
computer closed!

五、桥接模式

在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。

在提出桥梁模式的时候指出,桥梁模式的用意是”将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”。这句话有三个关键词,也就是抽象化、实现化和脱耦。

抽象化:存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。
实现化:抽象化给出的具体实现,就是实现化。
脱耦:所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。

下面我们来看看代码实例:

1
2
3
4
5
package com.model.structure;
public interface Driver { 
    public void connect(); 
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class MysqlDriver implements Driver {
    @Override
    public void connect() {
        System.out.println("connect mysql done!");
    }
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class DB2Driver implements Driver {
    @Override
    public void connect() {
        System.out.println("connect db2 done!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.model.structure;
public abstract class DriverManager {
    private Driver driver;
    public void connect() {
        driver.connect();
    }
    public Driver getDriver() {
        return driver;
    }
    public void setDriver(Driver driver) {
        this.driver = driver;
    }
}

1
2
3
4
5
6
7
8
9
package com.model.structure;
public class MyDriverManager extends DriverManager {
    public void connect() {
        super.connect();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.model.structure;
public class Client {
    public static void main(String[] args) {
        DriverManager driverManager = new MyDriverManager();
        Driver driver1 = new MysqlDriver();
        driverManager.setDriver(driver1);
        driverManager.connect();
        Driver driver2 = new DB2Driver();
        driverManager.setDriver(driver2);
        driverManager.connect();
    }
}

执行结果:

1
2
connect mysql done!
connect db2 done!

如果看完代码实例还不是很理解,我们想想如下两个维度扩展:(1)假设我想加一个OracleDriver,这是一个维度,很好理解,不多解释。(2)假设我们想在连接前后固定输出点什么,我们只需要加一个MyDriverManager2,代码如下:

1
2
3
4
5
6
7
8
9
10
11
package com.model.structure;
public class MyDriverManager2 extends DriverManager {
    public void connect() {
        System.out.println("before connect");
        super.connect();
        System.out.println("after connect");
    }
}

再将Client代码中的MyDriverManager 改成 MyDriverManager2 ,执行结果如下:

1
2
3
4
5
6
before connect
connect mysql done!
after connect
before connect
connect db2 done!
after connect

六、组合模式

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。

组合模式让你可以优化处理递归或分级数据结构。

《设计模式》:将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

涉及角色:

Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。

Leaf:在组合中表示叶子结点对象,叶子结点没有子结点。

Composite:定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

比如现实中公司内各部门的层级关系,请看代码:

Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.model.structure;
public abstract class Company {
    private String name;
    public Company() {
    }
    public Company(String name) {
        super();
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    protected abstract void add(Company company);
    protected abstract void romove(Company company);
    protected abstract void display(int depth);
}

Composite:定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.model.structure;
import java.util.ArrayList;
import java.util.List;
public class ConcreteCompany extends Company {
    private List<Company> cList;
    public ConcreteCompany() {
        cList = new ArrayList();
    }
    public ConcreteCompany(String name) {
        super(name);
        cList = new ArrayList();
    }
    @Override
    protected void add(Company company) {
        cList.add(company);
    }
    @Override
    protected void display(int depth) {
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(new String(sb) + this.getName());
        for (Company c : cList) {
            c.display(depth + 2);
        }
    }
    @Override
    protected void romove(Company company) {
        cList.remove(company);
    }
}

Leaf:在组合中表示叶子结点对象,叶子结点没有子结点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.model.structure;
public class HRDepartment extends Company {
    public HRDepartment(String name) {
        super(name);
    }
    @Override
    protected void add(Company company) {
    }
    @Override
    protected void display(int depth) {
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(new String(sb) + this.getName());
    }
    @Override
    protected void romove(Company company) {
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.model.structure;
public class FinanceDepartment extends Company {
    public FinanceDepartment(String name) {
        super(name);
    }
    @Override
    protected void add(Company company) {
    }
    @Override
    protected void display(int depth) {
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(new String(sb) + this.getName());
    }
    @Override
    protected void romove(Company company) {
    }
}

Client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.model.structure;
public class Client {
    public static void main(String[] args) {
        Company root = new ConcreteCompany();
        root.setName("北京总公司");
        root.add(new HRDepartment("总公司人力资源部"));
        root.add(new FinanceDepartment("总公司财务部"));
        Company shandongCom = new ConcreteCompany("山东分公司");
        shandongCom.add(new HRDepartment("山东分公司人力资源部"));
        shandongCom.add(new FinanceDepartment("山东分公司账务部"));
        Company zaozhuangCom = new ConcreteCompany("枣庄办事处");
        zaozhuangCom.add(new FinanceDepartment("枣庄办事处财务部"));
        zaozhuangCom.add(new HRDepartment("枣庄办事处人力资源部"));
        Company jinanCom = new ConcreteCompany("济南办事处");
        jinanCom.add(new FinanceDepartment("济南办事处财务部"));
        jinanCom.add(new HRDepartment("济南办事处人力资源部"));
        shandongCom.add(jinanCom);
        shandongCom.add(zaozhuangCom);
        Company huadongCom = new ConcreteCompany("上海华东分公司");
        huadongCom.add(new HRDepartment("上海华东分公司人力资源部"));
        huadongCom.add(new FinanceDepartment("上海华东分公司账务部"));
        Company hangzhouCom = new ConcreteCompany("杭州办事处");
        hangzhouCom.add(new FinanceDepartment("杭州办事处财务部"));
        hangzhouCom.add(new HRDepartment("杭州办事处人力资源部"));
        Company nanjingCom = new ConcreteCompany("南京办事处");
        nanjingCom.add(new FinanceDepartment("南京办事处财务部"));
        nanjingCom.add(new HRDepartment("南京办事处人力资源部"));
        huadongCom.add(hangzhouCom);
        huadongCom.add(nanjingCom);
        root.add(shandongCom);
        root.add(huadongCom);
        root.display(0);
    }
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
北京总公司
--总公司人力资源部
--总公司财务部
--山东分公司
----山东分公司人力资源部
----山东分公司账务部
----济南办事处
------济南办事处财务部
------济南办事处人力资源部
----枣庄办事处
------枣庄办事处财务部
------枣庄办事处人力资源部
--上海华东分公司
----上海华东分公司人力资源部
----上海华东分公司账务部
----杭州办事处
------杭州办事处财务部
------杭州办事处人力资源部
----南京办事处
------南京办事处财务部
------南京办事处人力资源部

七、享元模式

享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。

看下数据库连接池的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.model.structure;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;
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;
        }
    }
}

通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!

Java经典设计模式(2):七大结构型模式(附实例和详解)相关推荐

  1. Java设计模式之七大结构型模式

    总体来说设计模式分为三大类:创建型模式.结构型模式和行为型模式. 结构型模式,共有七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 其中适配器模式主要分为三类:类的适配 ...

  2. Java设计模式之七大结构型模式(附实例和详解)

    博主在大三的时候有上过设计模式这一门课,但是当时很多都基本没有听懂,重点是也没有细听,因为觉得没什么卵用,硬是要搞那么复杂干嘛.因此设计模式建议工作半年以上的猿友阅读起来才会理解的比较深刻.当然,你没 ...

  3. java面试题31:结构型模式中最体现扩展性的模式是()

    java面试题31:结构型模式中最体现扩展性的模式是() A:装饰模式 B:合成模式 C:桥接模式 D:适配器 蒙蔽树上蒙蔽果,蒙蔽树下你和我 结构型模式是描述如何将类对象结合在一起,形成一个更大的结 ...

  4. 设计模式总结之结构型模式

    设计模式总结之结构型模式 结构型模式描述如何组织类和对象以组成更大的结构.结构型类模式采用继承机制来组合接口和实现,结构型对象模式则采用组合聚合来组合对象以实现新功能,可以在运行时刻改变对象组合关系, ...

  5. 设计模式7大结构型模式

    2019独角兽企业重金招聘Python工程师标准>>> 结构型模式:结构型模式是描述如何将类对象结合在一起,形成一个更大的结构,结构模式描述两种不同的东西:类与类的实例.故可以分为类 ...

  6. iOS设计模式四部曲(二) 结构型模式 内附Demo

    本篇是四部曲的第二篇,第一篇请点这里iOS设计模式四部曲(一):创建型模式 内附Demo,关于设计模式强烈推荐图书<Head First设计模式>以及<研磨设计模式>.由于个人 ...

  7. 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)

    一.适配器模式(类适配器.对象适配器.接口适配器) 1.现实生活中的例子 泰国插座用的是两孔的(欧标),可以买个多功能转换插头(适配器),这样就可以使用了国内的电器了. 2.基本介绍 适配器模式(Ad ...

  8. 初探Java设计模式2:结构型模式(代理模式,适配器模式等)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. 《设计模式》3.结构型模式

    点击进入我的博客 3.1 适配器模式 适配器模式把一个类的接口变换成客户端所期待的另一种接口,使得原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 3.1.1 类的适配器结构 目标(Targe ...

  10. Java经典设计模式:五大创建型模式

    一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥 ...

最新文章

  1. 针对《评人工智能如何走向新阶段》一文,继续发布国内外的跟贴留言457-465条如下:
  2. 计算机网络 实验六 静态路由配置,实验六-静态路由配置.doc
  3. Apollo进阶课程 ⑧ | 高精地图的格式规范
  4. c printf 段错误_错误:预期声明在C中的printf之前指定
  5. mysql null 0 空_MySQL中 null与not null和null与空值''的区别
  6. 第一段冲刺 站立会议 5.5
  7. 2021-06-16单例模式详解
  8. Matlab2018破解方法
  9. 亚泰盛世携NB物理实验邀你莅临第66届中国教育装备展
  10. Mysql—— order 和 limit 的用法
  11. ASP.NET MVC入门视频教程
  12. 一封谷歌账号辅助邮箱变更的广告邮件
  13. 关于LYNC同步通讯录参数修改
  14. stm32mp15x环境搭建基于linux环境(上)
  15. /dev/mem可没那么简单
  16. 长春师范大学计算机学院宿舍,长春师范大学宿舍条件,宿舍环境图片(10篇)
  17. 开辟ORACLE 学习之路,努力的去成为DBA
  18. “国密证书全生态应用战略研讨会”在深圳隆重召开
  19. iClient for Leaflet加载MVT矢量瓦片并注册鼠标事件
  20. unity传统2D下落式音游制作(一)

热门文章

  1. 3.struts2中Action的三种写法
  2. C11简洁之道:函数绑定
  3. C# WPF DataGrid在Grid中自适应窗体大小
  4. MyBatis单表增删改查--接口实现
  5. 转python 发送邮件实例
  6. C#winform初试报表
  7. Servlet和JSP的异同。
  8. jQuery(非插件)制作商城放大镜效果
  9. SQL2000和SQL2005同时安装问题(转载)
  10. C#基于RabbitMQ实现客户端之间消息通讯实战演练