将程序分离成服务与对外窗口(介面),当外界要使用时,呼叫窗口即可,服务的一切不用知道。
起因是这样子,假如现在有一个平台,且支援三个服务,最直觉的设计方式,便是设计出独自连结服务的平台:
随着支援平台增加到三个,维持上一个设计,那会演变成:
由此可见,该模式的数量公式为:平台数量 X 服务数量 = 模式总量
。
长远来看,不是好的做法。
那不如把服务跟平台分离,服务归服务,平台归平台,换句话说,一个对内、一个对外,只要让对外的能调用对内的,同时没有错误产生,使用者自然觉得一切正常。
作法是:
Abstract Class
、Interface
。服务亲代:Train
public interface Train {
public abstract String checkName();
public abstract boolean isOnTime();
public abstract void setTime(int min);
public abstract void goToDestination();
public abstract boolean getToiletStatus();
public abstract void setToiletStatus(boolean using);
public abstract void moveOn();
public abstract void stop();
public abstract void getFoodByTrolleyService();
public abstract void timeNeedToArrive();
public abstract void getEmergencies();
}
服务子代:LocalTrain
、PuyumaExpress
、TarokoExpress
public class LocalTrain implements Train {
protected String name;
protected boolean onTime;
protected int delayMins;
protected boolean toiletInUsing;
protected boolean hasTrolleyService;
public LocalTrain() {
this.name = "区间车";
this.onTime = true;
this.delayMins = 0;
this.toiletInUsing = false;
this.hasTrolleyService = false;
}
@Override
public String checkName() {
return name;
}
@Override
public boolean isOnTime() {
return onTime;
}
@Override
public void setTime(int min) {
delayMins += min;
onTime = (delayMins < 0);
}
@Override
public void goToDestination() {
System.out.println("抵达目的地");
}
@Override
public boolean getToiletStatus() {
return toiletInUsing;
}
@Override
public void setToiletStatus(boolean using) {
toiletInUsing = using;
}
@Override
public void moveOn() {
System.out.println("列车向前");
}
@Override
public void stop() {
System.out.println("列车停驶");
}
@Override
public void getFoodByTrolleyService() {
System.out.println("难过,没有东西可买");
}
@Override
public void timeNeedToArrive() {
System.out.println("还需要 " + delayMins + "分钟才能抵达");
}
@Override
public void getEmergencies() {
// 1 - 5
int option = (int) (Math.random() * (6 - 1 + 1)) + 1;
switch (option) {
case 1:
System.out.println("撞倒擅闯平交道的车");
setTime(-50);
stop();
moveOn();
timeNeedToArrive();
goToDestination();
break;
case 2:
System.out.println("肚子有点饿,想买东西");
getFoodByTrolleyService();
setTime(11);
timeNeedToArrive();
goToDestination();
break;
case 3:
System.out.println("想上厕所但有人");
setToiletStatus(true);
getToiletStatus();
setTime(-1);
timeNeedToArrive();
goToDestination();
break;
case 4:
System.out.println("想上厕所");
setToiletStatus(false);
getToiletStatus();
setTime(-7);
timeNeedToArrive();
goToDestination();
break;
case 5:
System.out.println("一路顺畅");
timeNeedToArrive();
goToDestination();
break;
case 6:
System.out.println("座位没了,只好站着");
setTime(-12);
timeNeedToArrive();
goToDestination();
break;
}
}
}
public class PuyumaExpress implements Train {
protected String name;
protected boolean onTime;
protected int delayMins;
protected boolean toiletInUsing;
protected boolean hasTrolleyService;
public PuyumaExpress() {
this.name = "普悠玛";
this.onTime = true;
this.delayMins = 0;
this.toiletInUsing = false;
this.hasTrolleyService = true;
}
@Override
public String checkName() {
return name;
}
@Override
public boolean isOnTime() {
return onTime;
}
@Override
public void setTime(int min) {
delayMins += min;
onTime = (delayMins < 0);
}
@Override
public void goToDestination() {
System.out.println("很快抵达目的地");
}
@Override
public boolean getToiletStatus() {
return toiletInUsing;
}
@Override
public void setToiletStatus(boolean using) {
toiletInUsing = using;
}
@Override
public void moveOn() {
System.out.println("列车向前");
}
@Override
public void stop() {
System.out.println("列车停驶");
}
@Override
public void getFoodByTrolleyService() {
if (hasTrolleyService) {
System.out.println("服务员用推车贩售食物");
} else {
System.out.println("难过,没有东西可买");
}
}
@Override
public void timeNeedToArrive() {
System.out.println("还需要 " + delayMins + "分钟才能抵达");
}
@Override
public void getEmergencies() {
// 1 - 4
int option = (int) (Math.random() * (4 - 1 + 1)) + 1;
switch (option) {
case 1:
System.out.println("肚子有点饿,想买东西");
getFoodByTrolleyService();
setTime(-3);
timeNeedToArrive();
goToDestination();
break;
case 2:
System.out.println("上下车花费太多时间");
setTime(-15);
moveOn();
timeNeedToArrive();
goToDestination();
break;
case 3:
System.out.println("想上厕所");
setToiletStatus(false);
setTime(12);
getToiletStatus();
timeNeedToArrive();
goToDestination();
break;
case 4:
System.out.println("一路顺畅");
timeNeedToArrive();
goToDestination();
break;
}
}
}
public class TarokoExpress implements Train {
protected String name;
protected boolean onTime;
protected int delayMins;
protected boolean toiletInUsing;
protected boolean hasTrolleyService;
public TarokoExpress() {
this.name = "太鲁阁";
this.onTime = true;
this.delayMins = 0;
this.toiletInUsing = false;
this.hasTrolleyService = true;
}
@Override
public String checkName() {
return name;
}
@Override
public boolean isOnTime() {
return onTime;
}
@Override
public void setTime(int min) {
delayMins += min;
onTime = (delayMins < 0);
}
@Override
public void goToDestination() {
System.out.println("开心地抵达目的地");
}
@Override
public boolean getToiletStatus() {
return toiletInUsing;
}
@Override
public void setToiletStatus(boolean using) {
toiletInUsing = using;
}
@Override
public void moveOn() {
System.out.println("列车向前");
}
@Override
public void stop() {
System.out.println("列车停驶");
}
@Override
public void getFoodByTrolleyService() {
if (hasTrolleyService) {
System.out.println("服务员用推车贩售食物");
} else {
System.out.println("难过,没有东西可买");
}
}
@Override
public void timeNeedToArrive() {
System.out.println("还需要 " + delayMins + "分钟才能抵达");
}
@Override
public void getEmergencies() {
// 1 - 4
int option = (int) (Math.random() * (4 - 1 + 1)) + 1;
switch (option) {
case 1:
System.out.println("因为平交道上障碍物所以停车");
setTime(-50);
stop();
moveOn();
timeNeedToArrive();
goToDestination();
break;
case 2:
System.out.println("肚子有点饿,想买东西");
getFoodByTrolleyService();
setTime(220);
timeNeedToArrive();
goToDestination();
break;
case 3:
System.out.println("想上厕所但有人");
setToiletStatus(true);
getToiletStatus();
setTime(1);
timeNeedToArrive();
goToDestination();
break;
case 4:
System.out.println("一路顺畅");
timeNeedToArrive();
goToDestination();
break;
}
}
}
窗口亲代:Traveler
public interface Traveler {
public abstract void checkTicket(Train train);
public abstract void getJourney();
}
窗口子代:SingleTraveler
、FamilyTraveler
、ForeignTraveler
public class SingleTraveler implements Traveler {
private String name;
private Train ticket;
public SingleTraveler(String name) {
this.name = name;
}
@Override
public void checkTicket(Train train) {
this.ticket = train;
System.out.println("我是 " + name + ",确认车种为:" + ticket.checkName());
}
@Override
public void getJourney() {
System.out.println("本人 " + name + " 的旅途即将开始");
ticket.getEmergencies();
}
}
public class FamilyTraveler implements Traveler {
private String name;
private int children;
private Train ticket;
public FamilyTraveler(String name, int childrenCount) {
this.name = name;
this.children = childrenCount;
}
@Override
public void checkTicket(Train train) {
this.ticket = train;
System.out.println("我是 " + name + ",确认车种为:" + ticket.checkName());
}
@Override
public void getJourney() {
System.out.println("与 " + children + " 个孩子的旅途即将开始");
ticket.getEmergencies();
}
}
public class ForeignTraveler implements Traveler {
private String name;
private String country;
private Train ticket;
public ForeignTraveler(String name, String country) {
this.name = name;
this.country = country;
}
@Override
public void checkTicket(Train train) {
this.ticket = train;
System.out.println("My name is " + name + ",the train is:" + ticket.checkName());
}
@Override
public void getJourney() {
System.out.println("I miss my country: " + country + " , but the new journey is so adorable");
ticket.getEmergencies();
}
}
测试:JourneyBridgePatternSample
public class JourneyBridgePatternSample {
public static void main(String[] args) {
System.out.println("---一人的旅程开始---");
System.out.println("这次的车种是:区间车");
SingleTraveler singleTraveler = new SingleTraveler("维特");
singleTraveler.checkTicket(new LocalTrain());
singleTraveler.getJourney();
System.out.println("\n---下一组是家庭的旅程---");
System.out.println("车种为:普悠玛");
FamilyTraveler familyTraveler = new FamilyTraveler("罗杰", 3);
familyTraveler.checkTicket(new PuyumaExpress());
familyTraveler.getJourney();
System.out.println("\n---最後是外国人的旅程---");
System.out.println("虽然想家,仍把握机会搭乘:太鲁阁");
ForeignTraveler foreignTraveler = new ForeignTraveler("David", "US");
foreignTraveler.checkTicket(new TarokoExpress());
foreignTraveler.getJourney();
}
}
服务亲代:Train
/** @interface */
class Train {
constructor(name, hasTrolleyService) {
this.name = name;
this.onTime = true;
this.delayMins = 0;
this.toiletInUsing = false;
this.hasTrolleyService = hasTrolleyService;
}
/** @abstract */
checkName() { return; }
/** @abstract */
isOnTime() { return; }
/** @abstract */
setTime(min) { return; }
/** @abstract */
goToDestination() { return; }
/** @abstract */
getToiletStatus() { return; }
/** @abstract */
setToiletStatus(using) { return; }
/** @abstract */
moveOn() { return; }
/** @abstract */
stop() { return; }
/** @abstract */
getFoodByTrolleyService() { return; }
/** @abstract */
timeNeedToArrive() { return; }
/** @abstract */
getEmergencies() { return; }
}
服务子代:LocalTrain
、PuyumaExpress
、TarokoExpress
class LocalTrain extends Train {
constructor() {
super("区间车", false);
}
/** @override */
checkName() {
return this.name;
}
/** @override */
isOnTime() {
return this.onTime;
}
/** @override */
setTime(min) {
this.delayMins += min;
this.onTime = (this.delayMins < 0);
}
/** @override */
goToDestination() {
console.log("抵达目的地");
}
/** @override */
getToiletStatus() {
return this.toiletInUsing;
}
/** @override */
setToiletStatus(using) {
this.toiletInUsing = using;
}
/** @override */
moveOn() {
console.log("列车向前");
}
/** @override */
stop() {
console.log("列车停驶");
}
/** @override */
getFoodByTrolleyService() {
console.log("难过,没有东西可买");
}
/** @override */
timeNeedToArrive() {
console.log("还需要 " + this.delayMins + "分钟才能抵达");
}
/** @override */
getEmergencies() {
// 1 - 5
const option = Math.floor(Math.random() * (6 - 1 + 1)) + 1;
switch (option) {
case 1:
console.log("撞倒擅闯平交道的车");
this.setTime(-50);
this.stop();
this.moveOn();
this.timeNeedToArrive();
this.goToDestination();
break;
case 2:
console.log("肚子有点饿,想买东西");
this.getFoodByTrolleyService();
this.setTime(11);
this.timeNeedToArrive();
this.goToDestination();
break;
case 3:
console.log("想上厕所但有人");
this.setToiletStatus(true);
this.getToiletStatus();
this.setTime(-1);
this.timeNeedToArrive();
this.goToDestination();
break;
case 4:
console.log("想上厕所");
this.setToiletStatus(false);
this.getToiletStatus();
this.setTime(-7);
this.timeNeedToArrive();
this.goToDestination();
break;
case 5:
console.log("一路顺畅");
this.timeNeedToArrive();
this.goToDestination();
break;
case 6:
console.log("座位没了,只好站着");
this.setTime(-12);
this.timeNeedToArrive();
this.goToDestination();
break;
}
}
}
class PuyumaExpress extends Train {
constructor() {
super("普悠玛", true);
}
/** @override */
checkName() {
return this.name;
}
/** @override */
isOnTime() {
return this.onTime;
}
/** @override */
setTime(min) {
this.delayMins += min;
this.onTime = (this.delayMins < 0);
}
/** @override */
goToDestination() {
console.log("很快抵达目的地");
}
/** @override */
getToiletStatus() {
return this.toiletInUsing;
}
/** @override */
setToiletStatus(using) {
this.toiletInUsing = using;
}
/** @override */
moveOn() {
console.log("列车向前");
}
/** @override */
stop() {
console.log("列车停驶");
}
/** @override */
getFoodByTrolleyService() {
if (this.hasTrolleyService) {
console.log("服务员用推车贩售食物,买了鸡腿便当");
} else {
console.log("难过,没有东西可买");
}
}
/** @override */
timeNeedToArrive() {
console.log("还需要 " + this.delayMins + "分钟才能抵达");
}
/** @override */
getEmergencies() {
// 1 - 4
const option = Math.floor(Math.random() * (4 - 1 + 1)) + 1;
switch (option) {
case 1:
console.log("肚子有点饿,想买东西");
this.getFoodByTrolleyService();
this.setTime(-3);
this.timeNeedToArrive();
this.goToDestination();
break;
case 2:
console.log("上下车花费太多时间");
this.setTime(-15);
this.moveOn();
this.timeNeedToArrive();
this.goToDestination();
break;
case 3:
console.log("想上厕所");
this.setToiletStatus(false);
this.setTime(12);
this.getToiletStatus();
this.timeNeedToArrive();
this.goToDestination();
break;
case 4:
console.log("一路顺畅");
this.timeNeedToArrive();
this.goToDestination();
break;
}
}
}
class TarokoExpress extends Train {
constructor() {
super("太鲁阁", true);
}
/** @override */
checkName() {
return this.name;
}
/** @override */
isOnTime() {
return this.onTime;
}
/** @override */
setTime(min) {
this.delayMins += min;
this.onTime = (this.delayMins < 0);
}
/** @override */
goToDestination() {
console.log("开心地抵达目的地");
}
/** @override */
getToiletStatus() {
return this.toiletInUsing;
}
/** @override */
setToiletStatus(using) {
this.toiletInUsing = using;
}
/** @override */
moveOn() {
console.log("列车向前");
}
/** @override */
stop() {
console.log("列车停驶");
}
/** @override */
getFoodByTrolleyService() {
if (this.hasTrolleyService) {
console.log("服务员用推车贩售食物,买了排骨便当");
} else {
console.log("难过,没有东西可买");
}
}
/** @override */
timeNeedToArrive() {
console.log("还需要 " + this.delayMins + "分钟才能抵达");
}
/** @override */
getEmergencies() {
// 1 - 4
const option = Math.floor(Math.random() * (4 - 1 + 1)) + 1;
switch (option) {
case 1:
console.log("因为平交道上障碍物所以停车");
this.setTime(-50);
this.stop();
this.moveOn();
this.timeNeedToArrive();
this.goToDestination();
break;
case 2:
console.log("肚子有点饿,想买东西");
this.getFoodByTrolleyService();
this.setTime(20);
this.timeNeedToArrive();
this.goToDestination();
break;
case 3:
console.log("想上厕所但有人");
this.setToiletStatus(true);
this.getToiletStatus();
this.setTime(1);
this.timeNeedToArrive();
this.goToDestination();
break;
case 4:
console.log("一路顺畅");
this.timeNeedToArrive();
this.goToDestination();
break;
}
}
}
窗口亲代:Traveler
/** @interface */
class Traveler {
constructor(name) {
this.name = name;
this.ticket = null;
}
/** @abstract */
checkTicket(train) { return; }
/** @abstract */
getJourney() { return; }
}
窗口子代:SingleTraveler
、FamilyTraveler
、ForeignTraveler
class SingleTraveler extends Traveler {
constructor(name) {
super(name);
}
/** @override */
checkTicket(train) {
this.ticket = train;
console.log("我是 " + this.name + ",确认车种为:" + this.ticket.checkName());
}
/** @override */
getJourney() {
console.log("本人 " + this.name + " 的旅途即将开始");
this.ticket.getEmergencies();
}
}
class FamilyTraveler extends Traveler {
constructor(name, childrenCount) {
super(name);
this.children = childrenCount;
}
/** @override */
checkTicket(train) {
this.ticket = train;
console.log("我是 " + this.name + ",确认车种为:" + this.ticket.checkName());
}
/** @override */
getJourney() {
console.log("与 " + this.children + " 个孩子的旅途即将开始");
this.ticket.getEmergencies();
}
}
class ForeignTraveler extends Traveler {
constructor(name, country) {
super(name);
this.country = country;
}
/** @override */
checkTicket(train) {
this.ticket = train;
console.log("My name is " + this.name + ",the train is:" + this.ticket.checkName());
}
/** @override */
getJourney() {
console.log("I miss my country: " + this.country + " , but the new journey is so adorable");
this.ticket.getEmergencies();
}
}
测试:journeyBridgePatternSample
const journeyBridgePatternSample = () => {
console.log("---一人的旅程开始---");
console.log("这次的车种是:区间车");
const singleTraveler = new SingleTraveler();
singleTraveler.checkTicket(new LocalTrain());
singleTraveler.getJourney();
console.log("\n---下一组是家庭的旅程---");
console.log("车种为:普悠玛");
const familyTraveler = new FamilyTraveler("罗杰", 3);
familyTraveler.checkTicket(new PuyumaExpress());
familyTraveler.getJourney();
console.log("\n---最後是外国人的旅程---");
console.log("虽然想家,仍把握机会搭乘:太鲁阁");
const foreignTraveler = new ForeignTraveler("David", "US");
foreignTraveler.checkTicket(new TarokoExpress());
foreignTraveler.getJourney();
};
journeyBridgePatternSample();
Bridge 算是在开发上很常使用的模式,在於分离,让物件们可以专责在自己的功能上。过往的开发经验上,时常使用该模式,但省略使用虚拟层开规格这步骤。经由这次的学习,了解先写下规格後,方便之後开发服务时知道哪些功能要开发,而对外窗口在呼叫上也能省略再三确认的麻烦。
缺点也是十分明显:
这些仰赖经验来判断,讲多了还是亲自面对专案时,才能慢慢思考出合适的做法。
明天将介绍 Structural patterns 的第三个模式:Composite 模式。
>>: Batch Processing (4) - Materialization of Intermediate State
人的科技文明发展始终来自於人性 在科技进步的情况之下,我们已经习惯於使用科技的帮助来介入我们的生活,...
开启文字档案与写入资料 Python使用内建函式open()开启档案和close()关闭档案。 开启...
学习目标 if判断&switch case 、取得html元素 if判断 if(条件)-&g...
JavaScript(通常缩写为JS)是可以内嵌於网页中,是一个成熟的动态程序语言,在网站里加入互动...
昨天我们讨论的函式,是没有返回数值的函式,只是单纯传入参数做运算後,直接输出。但我们更多时候会需要把...