定义
要求一个子系统的外部与其内部的通信必须通过一个统一的接口对象进行。该模式提供一个高层次的接口,使得子系统更容易使用。
使用场景
为一个复杂子系统提供一个统一的简单接口。子系统往往因为不断演化而变得越来越复杂,甚至可能被替换。大多数模式使用时都会产生更多更小的类,这使子系统更具可重用性的同时也更容易对子系统进行定制、修改,这种易变形使得隐藏子系统的具体实现就变得尤为重要,外观模式可以提供一个简单统一的接口,对外隐藏子系统的具体实现、隔离变化。
当需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,可以让它们仅通过外观模式接口进行通信,从而简化它们之间的依赖关系。
关键点
一个对外通信的统一接口角色
一个或多个具体的内部角色—具体的内部通信细节
外观模式通过一个统一的接口对外提供服务,使得外部程序只通过一个类就可以实现系统内部的多种功能,而实现这些功能的内部子系统之间可能互相交互,如果没有进行封装,那么用户就需要操作几个复杂子系统的交互逻辑,容易出错。而通过外观类来屏蔽这些复杂的交互,降低用户的使用成本。
实现
/**
* 图片加载上下文—对外暴露加载图片的方法,对外屏蔽实现细节
*/
public class ImageLoader {
/**
* 具体的内部加载细节—抽象依赖
*/
private ImageLoaderStrategy mImageLoad;
/**
* 使用策略模式动态注入
*/
public void setImageLoadStrategy(ImageLoaderStrategy imageLoadStrategy) {
this.mImageLoad = imageLoadStrategy;
}
/**
* 对外提供的加载方法
*
* @param imageView
* @param url
*/
public void displayImage(ImageView imageView, String url) {
mImageLoad.displayImage(imageView, url);
}
/**
* * 对外提供的加载方法 携带占位符和加载失败显示的图片资源Id
*
* @param imageView
* @param url
* @param placeholder
* @param error
*/
public void displayImage(ImageView imageView, String url, int placeholder, int error) {
mImageLoad.displayImage(imageView, url, placeholder, error);
}
/**
* 加载圆角图片
*
* @param imageView
* @param url
* @param corner
*/
public void displayCornerImage(ImageView imageView, String url, int corner) {
mImageLoad.displayCornerImage(imageView, url, corner);
}
/**
* 私有化构造函数(通过单例对外提供)
*/
private ImageLoader() {
}
public static ImageLoader getInstance() {
return ImageLoadHolder.INSTANCE;
}
public static final class ImageLoadHolder {
private static final ImageLoader INSTANCE = new ImageLoader();
}
}
/**
* 图片加载策略定义(显示图片的策略)
*/
public interface ImageLoaderStrategy {
/**
* @param imageView
* @param url 图片资源地址
*/
void displayImage(ImageView imageView, String url);
/**
* @param imageView
* @param url 图片资源地址
* @param placeholder 占位图片资源id
* @param error 加载失败图片资源id
*/
void displayImage(ImageView imageView, String url, int placeholder, int error);
/**
* @param imageView
* @param url 图片资源地址
* @param corner 图片圆角
*/
void displayCornerImage(ImageView imageView, String url, int corner);
}
/**
* Glide图片加载策略(外观模式对外屏蔽其加载细节)
*/
public class GlideImageLoader implements ImageLoaderStrategy {
@Override
public void displayImage(ImageView imageView, String url) {
Glide.with(imageView.getContext())
.load(url)
.into(imageView);
}
@Override
public void displayImage(ImageView imageView, String url, int placeholder, int error) {
Glide.with(imageView.getContext())
.load(url)
.placeholder(placeholder)
.error(error)
.into(imageView);
}
@Override
public void displayCornerImage(ImageView imageView, String url, int corner) {
}
}
使用
ImageLoader.getInstance().displayImage();
小结
外观模式是一个使用频率较高的设计模式,它的精髓就在于封装二字。通过一个高层次结构为用户提供一个统一的API入口,使得用户通过一个类型就能基本操作整个系统,这样减少了用户的使用成本,也能狗提高系统的灵活性。
优点
1.对客户程序隐藏了子系统细节,因而减少了客户对子系统的耦合,能够拥抱变化
2.外观类对子系统的接口封装,使得系统更易于使用
缺点
1.外观类接口膨胀,由于子系统的接口都有外观类统一对外暴露,使得外观类的API接口较多,在一定程度上增加了用户的使用成本。
2.外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类。