1.适配器模式
适配器主要指的是对接口方法进行适配,看下面的例子:
package com.example;
public interface Phone {
public void time();
public void call() ;
}
package com.example;
public class Watch {
public void time() {
System.out.println("I am Watch:time");
}
}
首先,我们有一个电话接口,电话可以看时间,打电话,同时我们有一个手表类,手表只能看时间,如果我们现在要写一个类去实现电话接口,一般需要实现它里面的所有方法,但是我们已经有了Watch类,所以我们可以将Watch类用上,具体实现如下:
package com.example;
public class Telephone extends Watch implements Phone {
public void call() {
// TODO Auto-generated method stub
System.out.println("I am Telephone:call");
}
}
测试一下调用:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Phone phone=new Telephone();
phone.time();
phone.call();
}
}
结果:
可以看到,这里我们只实现了Phone的call接口,但是Telephone继承了Watch类,所以它有time方法,而且正好和Phone的time方法是同名同参数的,所以自动适配到了Phone接口的time方法,但是现实开发中,我们往往会碰到方法名或者参数不一样,但是同样功能的方法,我们就只能去显示的实现Phone的time接口了:
package com.example;
public class Telephone implements Phone {
public void call() {
// TODO Auto-generated method stub
System.out.println("I am Telephone:call");
}
public void time() {
// TODO Auto-generated method stub
new Watch().time();
}
}
另外,如果我们不想让Telephone有父类,或者Telephone有其他的父类要继承,因为java的单继承远程,我们也可以这么使用。
适配器模式可以理解为用已有的方法去实现同功能的接口,从而不至于造成同样的功能几个地方都有。还有,真实开发过程中,我们可以实现类和接口之间添加一些父类,这样可以更利于我们封装一些同功能的方法。
2.策略模式
程序里,我们经常会看到像下面:
int result=0;
if(flag==1){
//做一些计算得到result
}else if(flag==2){
//做另外一些计算得到result
}else{
//做另外一些计算得到result
}
如果这里面每个flag要做一些动作,那么这样的代码很不容易理解,而且也不方便拓展。于是我们可以创建一个这些操作的接口,然后每个flag对应的操作封装到不同实现这个接口的类型,比如:
package com.example;
public interface Calculator {
public int exec(int a,int b);
}
package com.example;
public class PlusCalculator implements Calculator {
public int exec(int a, int b) {
// TODO Auto-generated method stub
return a + b;
}
}
package com.example;
public class MinusCalculator implements Calculator {
public int exec(int a, int b) {
// TODO Auto-generated method stub
return a - b;
}
}
测试使用:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
int flag = 0;
Calculator calculator = null;
if (flag == 1) {
calculator = new PlusCalculator();
} else {
calculator = new MinusCalculator();
}
int result = calculator.exec(5, 3);
System.out.println(result);
}
}
这里演示的只是简单的加减,但是实际的业务算法一般是比较复杂,代码量比较多的,如果不封装,代码会难看;当然,我们也可以为这些实现类写个父类,因为一般的,这些实现类都会有一些公共的逻辑。
3.装饰模式
装饰模式也有人叫修饰模式,其实,装饰模式就是对一些操作增加一些功能,比如在操作之前记录操作日志,操作之后记录结果。
比如,上面我们定义了一个计算接口,并有两个类实现了接口,加法类PlusCalculator 和减法类MinusCalculator ,正常调用,我们只有结果,到底哪两个参数我们不知道:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Calculator plus = new AddCalculator();
int plusResult = plus.exec(5, 3);
System.out.println(plusResult);
Calculator minus = new MinusCalculator();
int minusResult = minus.exec(5, 3);
System.out.println(minusResult);
}
}
结果是:
8
2
现在我们可以创建装饰类,用来记录打印计算的参数:
package com.example;
public class Decorator implements Calculator {
Calculator calculator = null;
public Decorator(Calculator calculator) {
this.calculator = calculator;
}
public int exec(int a, int b) {
// TODO Auto-generated method stub
System.out.println("before:a=" + a + " b=" + b);
int result = calculator.exec(a, b);
System.out.println("after:save result:" + result);
return result;
}
}
把测试改一下,执行后得到结果:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Calculator plus = new Decorator(new PlusCalculator());
int plusResult = plus.exec(5, 3);
System.out.println(plusResult);
Calculator minus = new Decorator(new MinusCalculator());
int minusResult = minus.exec(5, 3);
System.out.println(minusResult);
}
}
这样,我们就记录到了参数信息,这种做法可以用法记录操作日志和结果,简单的说,装饰模式就是拓展一个类型的功能,而不是去方法调用处一个个去加,如果接口的某些方法不想用了,可以抛出提示。
4.代理模式
代理模式在形式上和装饰模式有点像,但是和装饰模式的功能不一样,装饰模式更像修饰,修饰一个 接口,然后实现接口的所有类都能被修饰到,所以装饰的对象一般都是接口,而代理模式充当的是中介者的角色,你要访问必须通过类A去访问类B,所以代理的对象一般都是真实的类对象,比如上面的加法类和减法类,我们可以创建他们的代理:
package com.example;
public class PlusProxy implements Calculator {
PlusCalculator calculator;
public PlusProxy() {
calculator = new PlusCalculator();
}
public int exec(int a, int b) {
// TODO Auto-generated method stub
System.out.println("before:a=" + a + " b=" + b + " a+b=?");
int result = calculator.exec(a, b);
System.out.println("after:a+b=" + result);
return result;
}
}
package com.example;
public class MinusProxy implements Calculator {
MinusCalculator calculator;
public MinusProxy() {
calculator = new MinusCalculator();
}
public int exec(int a, int b) {
// TODO Auto-generated method stub
System.out.println("before:a=" + a + " b=" + b + " a-b=?");
int result = calculator.exec(a, b);
System.out.println("after:a-b=" + result);
return result;
}
}
然后我们使用代理类去操作,而不是直接对用对应的计算类操作:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Calculator plus = new PlusProxy();
int plusResult = plus.exec(5, 3);
System.out.println(plusResult);
Calculator minus = new MinusProxy();
int minusResult = minus.exec(5, 3);
System.out.println(minusResult);
}
}
结果输出:
可以这么说,装饰模式和代理模式差不多,只是他们作用对象的区别.
5.模板设计模式
这个设计模式可以这么理解,把通用性的东西设置好,关键的部分放空,或者设置一个默认操作,然后使用模板是,只需要重写关键部分就可以了,换成类的方式去说就是,使用一个父类设计好模板,放出一些方法供子类实现或重写,比如:
package com.example;
public abstract class People {
protected abstract String getName();
protected abstract String getWord();
public void say() {
System.out.println(getName() + ":" + getWord());
}
}
我们有一个People类,它有三个方法,但是有两个方法没有具体实现,而是留给子类去实现,我们写两个类去实现它:
package com.example;
public class Teacher extends People {
@Override
protected String getName() {
// TODO Auto-generated method stub
return "老师";
}
@Override
protected String getWord() {
// TODO Auto-generated method stub
return "上课";
}
}
package com.example;
public class Student extends People {
@Override
protected String getName() {
// TODO Auto-generated method stub
return "学生";
}
@Override
protected String getWord() {
// TODO Auto-generated method stub
return "老师好";
}
}
我们测试调用:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
People teacher=new Teacher();
teacher.say();
People student=new Student();
student.say();
}
}
6.观察者模式
观察者模式有点像回调函数,有点像订阅,就是先订阅,当状态发生变化时再通知,比如:
package com.example;
public interface Observer {
public void send();
}
首先,我们有一个观察者接口,它有一个通知方法,就是通知订阅对象,QQ用户和微信用户都可以实现这个接口:
package com.example;
public class QQObserver implements Observer {
public void send() {
// TODO Auto-generated method stub
System.out.println("QQ received");
}
}
package com.example;
public class WxObserver implements Observer {
public void send() {
// TODO Auto-generated method stub
System.out.println("Wx received");
}
}
现在,观察者有两种类型,QQ用户和微信用户,然后我们可以定义一个博客类:
package com.example;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Blog {
List<Observer> list=new ArrayList<Observer>();
public void add(Observer obs) {
list.add(obs);
}
public void publish() {
System.out.println("new blog published");
Iterator<Observer> ite= list.iterator();
while (ite.hasNext()) {
Observer obs=ite.next();
obs.send();
}
}
}
博客可以通过add方法添加订阅对象,当博客发布后,就会去通知这些订阅的对象,我们测试一下:
package com.example;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Observer qq=new QQObserver();
Observer wx=new WxObserver();
Blog blog=new Blog();
blog.add(qq);//qq用户订阅
blog.add(wx);//微信用户订阅
blog.publish();//博客发布
}
}
总结:设计模式有很多种,但都是一些理解性的东西,自己动手敲敲代码能更好的理解,每种设计模式都特定的用处,要看具体情况具体看。不要认为设计模式很麻烦就不注重它,无数的经验告诉我们,一个好的程序设计能节省我们大量的时间和精力.