Fork me on GitHub

Java设计模式

设计模式分为三种类型,共23种:

  • 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
  • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  • 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。 实际上能够掌握其中几种常用的设计模式就很不错了。

代码风格良好的标准

如果想要确认代码编写风格是否良好,可以遵从以下两个标准:

  • 客户端(主方法)调用简单,不需要关注具体细节。
  • 程序代码的修改,不会影响到客户端的调用,即使用者可以不去关心代码是否变更。

以后编写代码要遵循这两个标准。

工厂设计模式(Factory)

我们通过一个例子来了解工厂设计模式。

首先,定义一个Fruit接口

1
2
3
4
5
package Factory.design;

public interface Fruit {
public void eat(); // 定义抽象方法
}

编写Apple类和Orange类实现Fruit接口

1
2
3
4
5
6
7
8
package Factory.design;

public class Apple implements Fruit {
@Override
public void eat(){
System.out.println("吃苹果");
}
}

1
2
3
4
5
6
7
8
package Factory.design;

public class Orange implements Fruit {
@Override
public void eat(){
System.out.println("吃橙子");
}
}

编写测试程序TestDemo

1
2
3
4
5
6
7
8
package Factory.design;

public class TestDemo {
public static void main(String[] args){
Fruit f=new Apple();
f.eat();
}
}

可以发现,上面的代码不是良好的代码编写风格。因为每次我们想实例化Fruit接口对象时,都需要通过子类来进行上转型操作。假设有另一个子类Orange也实现Fruit接口,当我们想得到Orange对象时,就需要修改客户端代码,也就是将Apple子类替换为Orange子类。那么,假设有很多子类实现了Fruit接口呢?

其实,在整个过程中,客户端只关心一件事:如何取得Fruit接口对象。至于这个接口是由那个子类对象实例化的客户端根本不需要知道,所以最大问题就在关键字new的使用上

那么,如何解决关键字new带来的耦合度问题呢?解决办法是让客户端只看见接口而不让其看见子类,但是需要一个中间工具类(也就是Factory工厂类)来取得接口对象。这样客户端就不需要关心接口子类,只要通过Factory工厂类就可以获取接口对象。

增加一个工厂类进行过渡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Factory.design;

public class Factory { // 定义工厂类,此类不提供属性
/**
* 取得指定类型的接口对象
* @param className 要取得的类实例化对象标记
* @return 如果指定标记存在,则Fruit接口实例化相应对象,否则返回null
*/
public static Fruit getInstance(String className){
if("apple".equals(className)){ // 是否是苹果类
return new Apple();
}else if("orange".equals(className)){// 是否是橙子类
return new Orange();
}else{
return null; // 没有实例化对象会造成NullPointerException,这里再编写一个Other类实现Fruit接口,然后在这里实例化Other子类对象,就不会出现NullPointerException
}
}
}

相应的客户端代码:

1
2
3
4
5
6
7
8
package Factory.design;

public class TestDemo {
public static void main(String[] args){
Fruit f=Factory.getInstance("orange"); // 通过工厂类取得指定接口对象
f.eat(); // 调用接口方法
}
}

通过使用Factory.getInstance()方法根据指定子类的标记取得接口实例化对象,使得客户端不需要再关注具体子类,也不需要关注Factory类是怎么处理的,只需要关注如何取得接口对象,如何进行操作。这样的设计模式就是工厂设计模式。

代理设计模式

代理设计也是在java开发中使用较多的一种设计模式,所谓的代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理,就好比在生活中经常使用到的代理上网那样,客户通过网络代理连接网络,由代理服务器完成用户权限,访问限制等与上网操作相关的操作。
代理设计模式1
代理设计模式2

用户只关注浏览网页这个功能,而其他业务操作(如:检查用户身份)交给代理服务器处理。

1
2
3
4
5
package proxy.design;

public interface NetWork { // NetWork接口
public void browse(); // 定义浏览网页的方法
}

1
2
3
4
5
6
7
8
package proxy.design;

public class Custom implements NetWork { // 实现了Network接口的用户端
@Override
public void browse() {
System.out.println("客户端浏览网页");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package proxy.design;

public class Proxy implements NetWork { // 代理上网
private NetWork netWork;
public Proxy(NetWork netWork){ // 设置代理的真实操作
this.netWork=netWork; // 设置代理的子类
}

public void check(){ // 与上网相关的具体操作
System.out.println("代理服务器检查用户是否合法");
}
@Override
public void browse() {
this.check(); // 同时调用多个与具体业务相关的操作
this.netWork.browse(); // 调用真实上网操作
}
}
1
2
3
4
5
6
7
8
package proxy.design;

public class TestDemo {
public static void main(String args[]){
NetWork netWork=new Proxy(new Custom()); // 通过代理服务器检查用户是否合法
netWork.browse(); // 用户只关心上网浏览这个功能
}
}

单例模式

参考单例设计模式完全解析

参考简书-java常用十种设计模式