设计模式:适配器模式与外观模式

适配器模式:将一个类的接口,转化成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。

适配器模式可以让类实现伪装,火鸡类可以调用鸭子类的方法,实际上还是调用自己的方法,这是因为适配器将两个不兼容的类的方法进行了转换,以下是代码来实现:

//这是两个不兼容的类,有自己不同的方法
public interface Duck {
	void gagaga();
	void fly();
}
public class DuckImpl implements Duck {
	public void gagaga() {
		System.out.println("嘎嘎嘎");
	}
	public void fly() {
		System.out.println("我可以一次飞5米");
	}
}

public interface Chicken {
	void jijiji();
	void fly();
}
public class ChickenImpl implements Chicken {
	public void jijiji() {
		System.out.println("叽叽叽");
	}
	public void fly() {
		System.out.println("我可以一次飞1米");
	}
}
//我们用适配器来将Chicken转换一下,使它可以调用Duck的方法
public class Adapter implements Duck {
	Chicken chicken;
	
	public Adapter(Chicken chicken) {
		this.chicken = chicken;
	}

	@Override
	public void gagaga() {
		chicken.jijiji();
	}

	@Override
	public void fly() {
		for (int i = 0; i < 5; i++) {
			chicken.fly();
		}
	}
}
//测试一下
public class Test {
	public static void main(String[] args) {
		ChickenImpl chicken = new ChickenImpl();
		Adapter adapter = new Adapter(chicken);
		
		adapter.gagaga();
		adapter.fly();
	}
}

Adapter相当于一个转换插头 

设计模式:适配器模式与外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 

如果我们设计了一个家庭影院,影院设备有DVD,投影仪,音响等等,看电影之前我们要做一系列事情,例如,把灯光调暗,打开DVD,打开投影仪......如果可以一键完成这些事情多好,外观模式就是要帮你集成这些功能,提供更直接的操作,它并不是将这些方法类封装,只是集成,如果觉得灯光太暗或者其他,我们还是可以单独调亮。

//外观类
public class Faced(){
    DVD dvd;
    Light light;
    Projector projector;
    ...
    public Faced(dvd, light, projector, ...){
    this.dvd = dvd;
    this.light = light;
    ...
    }

    public void watchMovie(){
    dvd.on();
    light.on();
    ...
    }

    public void endMovie(){
    dvd.off();
    light.off();
    ...
    }
}

可以看出外观模式的好处是:简化了设备的接口,同时降低了客户端和各个设备的耦合。例如,影院设备进行了升级,那么也只需要在外观的实现方法中修改该设备的方法即可,不用去修改客户端代码。

外观模式需要注意的地方

外观封装了子设备的类,那么客户端是如何调用子设备的方法的?

通过上面的代码可以看出,每一个单独的设备的方法的调用我们也是将设备的方法封装到了外观类中,这里使用了一个原则:

最少知识原则:只和你的密友谈话。

客户端只和外观谈话,不和子设备,如DVD,音响等谈话,降低了客户端和设备的耦合度。

下面给出最少知识原则的指导思想:

就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

1.该对象本身

2.被当做方法的参数而传过来的对象

3.该方法所创建或实例化的任何对象

4.对象的任何组件

尽管我们有时可以在客户端使用dvd.on();但是最好也不要使用,因为客户端这样不仅耦合了dvd类还耦合了on。所以尽可能自己封装子设备的方法,以便减少客户端和子设备的耦合。

适配器、外观、装饰者模式对比:

在介绍装饰者模式时,引出了一个开闭原则,即对修改关闭,对扩展开放。装饰者模式主要强调的是在不改变原有类的基础上,添加新功能。

适配器模式,主要是对适配对象进行调整,以便适合消费者的需求。从而达到消费者和被适配者解耦的目的。

外观模式的特点主要是简化接口,以及减少客户端对外观组件的耦合。因为如果客户端变化来,组件的子系统变化了,不用影响客户端。除此之外,在封装组件时,适当的在外观类中添加一些自己想要的规则。如上面例子中各设备的开关顺序等等