1.场景问题解决
1.1 场景描述
遥控器项目:电视厂商在电视机中预留了接口,遥控器外包给外部生产.
需要设计遥控器的功能.当前有LG电视机和sony电视机,提供各自接口,需要生产各自的遥控器.
用继承的方式,给每个电视厂商编写各自的遥控器.
1.2 OO设计
自己遥控器设置了一个接口,为不用的厂家单独设计遥控器(集成商家的接口. ).
[外链图片转存失败(img-L33AxZUm-1567956931412)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/15%E6%A1%A5%E6%8E%A5%E6%A8%A1%E5%BC%8F-1-oo.png)]
[外链图片转存失败(img-ktWjNXYF-1567956931413)(https://github.com/bobshute/public/blob/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/15%E6%A1%A5%E6%8E%A5%E6%A8%A1%E5%BC%8F-1-oo.png)]
- 基本类 Control,LGControl,SharpControl,SonyControl(电视机厂商的接口与电视内置实现)
public interface Control {
public void On();
public void Off();
public void setChannel(int ch);
public void setVolume(int vol);
}
public class LGControl implements Control {
@Override
public void On() {
System.out.println("**Open LG TV**");
}
@Override
public void Off() {
System.out.println("**Off LG TV**");
}
@Override
public void setChannel(int ch) {
System.out.println("**The LG TV Channel is setted "+ch+"**");
}
@Override
public void setVolume(int vol) {
System.out.println("**The LG TV Volume is setted "+vol+"**");
}
}
public class SonyControl implements Control {
@Override
public void On() {
System.out.println("*Open Sony TV*");
}
@Override
public void Off() {
System.out.println("*Off Sony TV*");
}
@Override
public void setChannel(int ch) {
System.out.println("*The Sony TV Channel is setted "+ch+"*");
}
@Override
public void setVolume(int vol) {
System.out.println("*The Sony TV Volume is setted "+vol+"*");
}
}
public class SharpControl implements Control {
@Override
public void On() {
System.out.println("***Open Sharp TV***");
}
@Override
public void Off() {
System.out.println("***Off Sharp TV***");
}
@Override
public void setChannel(int ch) {
System.out.println("***The Sharp TV Channel is setted "+ch+"***");
}
@Override
public void setVolume(int vol) {
System.out.println("***The Sharp TV Volume is setted "+vol+"***");
}
}
- oo设计时的实现方式
-
- TvControl,LGTvControl,SonyTvControl
-
- 外包遥控器接口及实现
public interface TvControl {
public void Onoff();
public void nextChannel();
public void preChannel();
}
public class LGTvControl extends LGControl implements TvControl{
//当前频道
private static int ch=0;
//当前电视开关状态
private static boolean ison=false;
public void Onoff(){
if(ison){
ison=false;
super.Off();
}else{
ison=true;
super.On();
}
}
public void nextChannel(){
ch++;
super.setChannel(ch);
}
public void preChannel(){
ch--;
if(ch<0){
ch=200;
}
super.setChannel(ch);
}
}
public class SonyTvControl extends SonyControl implements TvControl{
//当前频道
private static int ch=0;
//当前电视开关状态
private static boolean ison=false;
public void Onoff(){
if(ison){
ison=false;
super.Off();
}else{
ison=true;
super.On();
}
}
public void nextChannel(){
ch++;
super.setChannel(ch);
}
public void preChannel(){
ch--;
if(ch<0){
ch=200;
}
super.setChannel(ch);
}
}
public class MainTest {
public static void main(String[] args) {
LGTvControl mLGTvControl=new LGTvControl();
SonyTvControl mSonyTvControl=new SonyTvControl();
mLGTvControl.Onoff();
mLGTvControl.nextChannel();
mLGTvControl.nextChannel();
mLGTvControl.preChannel();
mLGTvControl.Onoff();
mSonyTvControl.Onoff();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.Onoff();
}
}
1.3 需求变动
- 新的电视机厂商
- 遥控器也增加新功能,需要直接跳转到某频道.
1.4 带来问题
那么就要修改原遥控器,
2.用设计模式改进
2.1 分析
新增抽象类中组合使用接口.
[外链图片转存失败(img-IrQF6jLD-1567956931414)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/15%E6%A1%A5%E6%8E%A5%E6%A8%A1%E5%BC%8F-1-%E6%A1%A5%E6%8E%A5%E6%A8%A1%E5%BC%8F.png)]
桥接模式:将实现(桥左侧上与下一起)与抽象(桥右侧上与下一起)放在两个不同的类层次中,使两个层次可以独立改变
2.2 重新设计
- TvControlabs 新的遥控抽象类
-
- TvControl 和oo设计一样的遥控板
-
- newTvControl 新款遥控板
-
- TestBridge 测试类
不用为每个厂商类单独设计遥控板,而是通用
新的遥控板功能模板不用修改原设计,新增新遥控板即可
public abstract class TvControlabs {
//oo代码中的Control
Control mControl=null;
public TvControlabs(Control mControl){
this.mControl=mControl;
}
public abstract void Onoff();
public abstract void nextChannel();
public abstract void preChannel();
}
public class TvControl extends TvControlabs {
private int ch=0;
private boolean ison=false;
public TvControl(Control mControl){
super(mControl);
}
@Override
public void Onoff() {
if(ison){
ison=false;
mControl.Off();
}else{
ison=true;
mControl.On();
}
}
@Override
public void nextChannel() {
ch++;
mControl.setChannel(ch);
}
@Override
public void preChannel() {
ch--;
if(ch<0){
ch=200;
}
mControl.setChannel(ch);
}
}
public class newTvControl extends TvControlabs {
private int ch=0;
private boolean ison=false;
private int prech=0;
public newTvControl(Control mControl) {
super(mControl);
}
@Override
public void Onoff() {
if(ison){
ison=false;
mControl.Off();
}else{
ison=true;
mControl.On();
}
}
@Override
public void nextChannel() {
prech=ch;
ch++;
mControl.setChannel(ch);
}
@Override
public void preChannel() {
prech=ch;
ch--;
if(ch<0){
ch=200;
}
mControl.setChannel(ch);
}
public void setChannel(int nch){
prech=ch;
ch=nch;
mControl.setChannel(ch);
}
public void Back(){
mControl.setChannel(prech);
}
}
public class TestBridge {
public static void main(String[] args) {
TvControl mLGTvControl;
TvControl mSonyTvControl;
mSonyTvControl=new TvControl(new SonyControl());
mLGTvControl=new TvControl(new LGControl());
mLGTvControl.Onoff();
mLGTvControl.nextChannel();
mLGTvControl.nextChannel();
mLGTvControl.preChannel();
mLGTvControl.Onoff();
mSonyTvControl.Onoff();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.Onoff();
newTvControl mSharpTvControl;
mSharpTvControl=new newTvControl(new SharpControl());
mSharpTvControl.Onoff();
mSharpTvControl.nextChannel();
mSharpTvControl.setChannel(9);
mSharpTvControl.setChannel(28);
mSharpTvControl.Back();
mSharpTvControl.Onoff();
}
}
3.设计模式总结
3.1 定义
桥接模式:将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变
3.2 分析思路
系统有多维角度分类时,而每一种分类又有可能变化,考虑使用桥接模式
桥接的目的是分离抽象与实现,使抽象和实现可以独立变化。
3.3 与其它模式对比
- 桥接的目的是让底层实现和上层接口可以分别演化,从而提高移植性
- 策略的目的是将复杂的算法封装起来,从而便于替换不同的算法
- 桥接模式是往往是为了利用已有的方法或类
- 策略模式是为了扩展和修改,并提供动态配置
- 桥接模式强调接口对象仅提供基本操作
- 策略模式强调接口对象提供的是一种算法
4. 设计模式使用场景及注意
5.参考文章
内容总计于HeadFirst设计模式及相关视频