java程序的设计原则
6大原则:
单一职责:一个类和方法只做一件事。
开闭原则:对修改关闭,对扩展开发。
里氏替换原则:子类可扩展新方法,但不可修改父类已有方法(父类已提供了具体实现的方法)。
依赖倒置:依赖于抽象,而非具体实现,即面向接口编程(如方法参数,类属性使用接口声明,这样可接收任何子类)。
接口隔离:使用多个隔离的接口定义抽象,降低耦合。
最少知道/迪米特原则:降低类之间的依赖,聚合,组合等。
1:门面设计模式
门面设计模式使用的场景是,当存在多个独立的子系统
时,执行某些操作可能需要子系统中的一个或者是多个,对于客户端来说具有一定的复杂度需要了解每个子系统都提供了哪些类,以及使用哪些类来完成操作
,此时就可以考虑使用门面设计模式,使用门面类来封装复杂操作,对客户端只提供一个简单的方法即可。比如我们常用的日志系统 ,有log4j,log4j2,logback,jul,simplelog等,但是用户在使用时只会使用其中一种的日志实现,用户只需要使用统一的日志接口就可以了,而不需要关心具体的日志实现都有哪些类,都有哪些方法,可以参考如下2个图:
与之类似的场景我们都可以优先考虑使用门面设计模式,对用户隐藏底层复杂度,降低用户使用难度。
1.1:场景
比如一件房子,有1个厕所,厕所都有若干个灯,有1个厨房,厨房也有若干个灯,有一个客厅,客厅也有若干个灯,然后呢还有几件卧室,也都有若干个灯,对于每个灯都有自己独立的开关,但是呢为了方便开关灯,会有一个总的开关来控制所有灯的开关,对于厨房,厕所,客厅,卧室也都有控制各自区域的开关,这些控制一批灯状态的开关,就类似于本文要分析的门面设计模式中的门面,如下图:
下面我们来看下如何通过程序实现。
1.2:程序实现
1.2.1:定义开关接口
为了满足依赖倒置
肯定要先定义接口。
public interface OnOff {
int ON_OFF_ON = 0;
int ON_OFF_OFF = 1;
// 开灯
void on();
// 关灯
void off();
}
1.2.2:定义各个区域灯开关子系统
public class KitchenOnOff implements OnOff {
private String area = "厨房";
// 厕所所有的灯
private List<Lamp> lampList = new ArrayList() {
{
// 所有的灯默认关闭
add(new Lamp(OnOff.ON_OFF_OFF, area + "1号灯"));
add(new Lamp(OnOff.ON_OFF_OFF, area + "2号灯"));
}
};
@Override
public void on() {
System.out.println("打开" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_ON));
System.out.println("打开" + area + "所有灯结束!");
}
@Override
public void off() {
System.out.println("关闭" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_OFF));
System.out.println("关闭" + area + "所有灯结束!");
}
}
public class SittingRoomOnOff implements OnOff {
private String area = "客厅";
// 厕所所有的灯
private List<Lamp> lampList = new ArrayList() {
{
// 所有的灯默认关闭
add(new Lamp(OnOff.ON_OFF_OFF, area + "1号灯"));
add(new Lamp(OnOff.ON_OFF_OFF, area + "2号灯"));
}
};
@Override
public void on() {
System.out.println("打开" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_ON));
System.out.println("打开" + area + "所有灯结束!");
}
@Override
public void off() {
System.out.println("关闭" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_OFF));
System.out.println("关闭" + area + "所有灯结束!");
}
}
public class WcOnOff implements OnOff {
private String area = "厕所";
// 厕所所有的灯
private List<Lamp> lampList = new ArrayList() {
{
// 所有的灯默认关闭
add(new Lamp(OnOff.ON_OFF_OFF, area + "1号灯"));
add(new Lamp(OnOff.ON_OFF_OFF, area + "2号灯"));
}
};
@Override
public void on() {
System.out.println("打开" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_ON));
System.out.println("打开" + area + "所有灯结束!");
}
@Override
public void off() {
System.out.println("关闭" + area + "所有灯开始!");
lampList.stream().forEach(o -> o.setOnOff(OnOff.ON_OFF_OFF));
System.out.println("关闭" + area + "所有灯结束!");
}
}
1.2.3:定义门面类
public class OnOffFacade {
// 使用接口定义引用,满足依赖倒置原则
private /*KitchenOnOff*/ OnOff kitchenOnOff;
// 使用接口定义引用,满足依赖倒置原则
private /*SittingRoomOnOff*/ OnOff sittingRoomOnOff;
// 使用接口定义引用,满足依赖倒置原则
private /*WcOnOff*/ OnOff wcOnOff;
public OnOffFacade() {
// 创建相关区域的开关类
this.kitchenOnOff = new KitchenOnOff();
this.sittingRoomOnOff = new SittingRoomOnOff();
this.wcOnOff = new WcOnOff();
}
// 关闭厕所灯
public void turnOffWcLamp() {
this.wcOnOff.off();
}
// 注意:该方法就体现了门面的真正价值,用户只需要知道要关闭厕所灯和客厅灯时调用该方法即可,而不需要知道厕所灯子系统和客厅灯子系统的存在,降低了使用者的复杂度
// 关闭厕所灯,客厅灯
public void turnOffWcAndSittingRoomLamp() {
this.wcOnOff.off();
this.sittingRoomOnOff.off();
}
// 注意:该方法就体现了门面的真正价值,用户只需要知道要关闭厕所灯和客厅灯时调用该方法即可,而不需要知道都有哪些灯子系统的存在,降低了使用者的复杂度
// 关闭所有区域的灯
public void turnOffAllLamp() {
this.wcOnOff.off();
this.sittingRoomOnOff.off();
this.kitchenOnOff.off();
}
}
1.2.4:测试
public class FacadeMain {
public static void main(String[] args) {
OnOffFacade onOffFacade = new OnOffFacade();
onOffFacade.turnOffWcLamp();
System.out.println("****************");
onOffFacade.turnOffWcAndSittingRoomLamp();
System.out.println("****************");
onOffFacade.turnOffAllLamp();
}
}
运行:
关闭厕所所有灯开始!
关闭厕所所有灯结束!
****************
关闭厕所所有灯开始!
关闭厕所所有灯结束!
关闭客厅所有灯开始!
关闭客厅所有灯结束!
****************
关闭厕所所有灯开始!
关闭厕所所有灯结束!
关闭客厅所有灯开始!
关闭客厅所有灯结束!
关闭厨房所有灯开始!
关闭厨房所有灯结束!
参考文章列表
设计模式(九)外观模式Facade(结构型) 。