前俩天老妈说从家里抽屉里找到个耳机但是用不了,我让她拍个照片给我看,原来是因为手机是Type-C接口,耳机是3.5mm头的。于是我买了个转接口给她。如下图:
本能反应的我,立马开始联想了起来…
适配器
情景1 没有耳机
mom的手机
public class MomPhone {
private TypeC earphone;
public void play(){
if (earphone == null) {
System.out.println("loudspeaker play");
} else {
System.out.println(earphone.getType() + " earphone play");
}
}
public void connect(TypeC earphone){
this.earphone = earphone;
}
}
播放状态是扬声器外放
MomPhone momPhone = new MomPhone();
momPhone.play(); // loudspeaker play
情景2 连接Type-C接口的华为耳机
public interface TypeC {
String getType();
}
public class TypeCHW implements TypeC {
@Override
public String getType() {
return "Huawei";
}
}
播放状态是华为耳机播放
momPhone.connect(new TypeCHW());
momPhone.play(); // Huawei earphone play
情景3 连接3.5mm的JBL耳机
public interface M35 {
String getType();
}
public class M35JBL implements M35 {
@Override
public String getType() {
return "JBL";
}
}
接口不对应是不能使用的,所以需要一个如图的转接头
public class Adapter implements TypeC{
private M35 m35;
public Adapter(M35 m35) {
this.m35 = m35;
}
@Override
public String getType() {
return m35.getType();
}
}
转接头需要连接手机,所以必须实现Type-C接口,并且暴露一个3.5mm接口,让3.5mm的设备连接自己,就是Adapter的构造方法。
有了转接口就可以播放了
momPhone.connect(new Adapter(new M35JBL()));
momPhone.play(); // JBL earphone play
适配器模式
情景3中将3.5mm设备通过转接口连接上Type-C接口的设备的过程,就是使用了设计模式中适配器模式,那个转接头就是适配器。
适配器模式可以分为类适配、对象适配、接口适配,上面用的就是对象适配。
类适配
public class M35JBLAdapter extends M35JBL implements TypeC {
@Override
public String getType() {
return super.getType();
}
}
要描述上面这个类,可以理解JBL的厂商将原来的JBL耳机升级为Type-C接口一样,是专门针对M35JBL这款设备做了适配一样。
momPhone.connect(new M35JBLAdapter());
momPhone.play(); // JBL earphone play
接口适配
这种模式在业务代码中应该很少遇到。大致描述就是说,有一个接口中定义了很多方法,如果想只实现其中部分的话,可以在接口和实现类中增加一层抽象类,抽象类实现接口所有方法,但是都是空实现,自定义类继承抽象类可以重写其中部分方法。
public interface A {
void a();
void b();
void c();
void d();
void e();
void f();
void g();
void h();
}
public abstract class AbstractA implements A {
public void a() {}
public void b() {}
public void c() {}
public void d() {}
public void e() {}
public void f() {}
public void g() {}
public void h() {}
}
public class AImpl extends AbstractA {
public void b() {
System.out.println();
}
public void e() {
System.out.println();
}
}
其中的AbstractA类就是适配器。
策略模式
策略模式大多情况用在根据不同角色(或类型)处理不同业务的场景中(比如游客、VIP、活动送的VIP)。举个例子:
if ("tourists".equals(type)) {
// 业务a
} else if ("vip".equals(type)) {
// 业务a
} else if ("presenterVip".equals(type)) {
// 业务a
} else {
// 业务a
}
随着业务代码行数比较多的时候,将每个业务代码提成一个单独的方法,可读性很高。直到增加了一个为 SVIP 的类型,原来的业务方法可能也需要拆分,于是决定将每个方法都独立成一个类。
public interface Role {
void run();
}
public class VIP implements Role {
@Override
public void run() {
// vip
}
}
public class SVIP implements Role {
@Override
public void run() {
// 金主爸爸,什么权限都开
}
}
public class Tourists implements Role {
@Override
public void run() {
// 穷b,不需要操作
return;
}
}
public class PVIP implements Role{
@Override
public void run() {
// 活动送的vip,只设置头像挂饰
}
}
另外定义一个业务类,将业务方法抽取出来
public class RoleService {
private Role role;
public RoleService(Role role){
this.role = role;
}
public void run(){
role.run();
}
}
最初的调用方式变成了下面这样:
Role role = null;
if ("tourists".equals(type)) {
role = new Tourists();
} else if ("vip".equals(type)) {
role = new VIP();
} else if ("presenterVip".equals(type)) {
role = new PVIP();
} else if ("svip".equals(type)){
role = new SVIP();
}
RoleService roleService = new RoleService(role);
roleService.run(); // 业务a
如果再次增加一种类型,同样执行业务a,那么扩展Role接口的实现类即可(程序设计开闭原则:对扩展开放,对修改关闭),以上改进流程就是运用了策略设计模式。每种角色有单独的实现类后,其中只包含该角色应该要做的业务,不和其他角色业务混在一起(单一职能原则),降低业务间的耦合。
但是貌似这么多if-else还是没有删除,还是要修改if-else内容。其实这块代码可以抽象成工厂方法,需要根据type获取对应角色实现类,用在程序其他地方。
简单工厂模式
public class RoleFactory {
public static Role create(String type) {
if ("tourists".equals(type)) {
return new Tourists();
} else if ("vip".equals(type)) {
return new VIP();
} else if ("presenterVip".equals(type)) {
return new PVIP();
} else if ("svip".equals(type)){
return new SVIP();
} else {
throw new RuntimeException("Type Error");
}
}
}
使用简单工厂
Role role = RoleFactory.create(type);
RoleService roleService = new RoleService(role);
roleService.run(); // 业务a
最后
刚开始写代码的时候并不知道设计模式有什么用,感觉花里胡哨还把自己绕晕了,直到在多个项目中由于需求的增加,发现自己写的代码改起来越来越费劲,慢慢的重构改进后,有一天发现自己原来用了设计模式(第一个是策略模式)。那么下次遇到这种业务场景,开始就按一种模式设计后,不论是后期优化还是扩展都很方便,而且代码的可读性也很好。
每个人对设计模式态度是不一样的,站的高度不同,看法也不同。“看山是山,看水是水;看山不是山,看水不是水;看山还是山,看水还是水”。不知道自己何时能修炼到那个境界。