设计模式 在线

2263外观模式

感觉电脑的例子更形象:

电脑整机是 CPU、内存、硬盘的外观。有了外观以后,启动电脑和关闭电脑都简化了。

直接 new 一个电脑。

在 new 电脑的同时把 cpu、内存、硬盘都初始化好并且接好线。

对外暴露方法(启动电脑,关闭电脑)。

启动电脑(按一下电源键):启动CPU、启动内存、启动硬盘

关闭电脑(按一下电源键):关闭硬盘、关闭内存、关闭CPU

更多参考内容

2262装饰器模式

复杂些的实例

在《绝地求生:刺激战场》游戏里面我们都知道。

  • Kar 98K有5发子弹;
  • 装上弹匣后有10发子弹;
  • 装上4倍镜后可以进行4倍瞄准;
  • 装上8倍镜后可以进行4倍瞄准、8倍瞄准。

枪具有开火功能:

public interface Gun {
    /** * 开火直至打空子弹 */
    public void fire();
}

public class Kar98K implements Gun {
    @Override
    public void fire() {
        System.out.println("砰*5");
    }
}

装饰上弹匣变更枪开火功能:

public abstract class AbstractMagazine implements Gun {
    private Gun gun;

    public AbstractMagazine(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Magazine extends AbstractMagazine {
    public Magazine(Gun gun) {
        super(gun);
    }

    @Override
    public void fire() {
        System.out.println("砰*10");
    }
}
测试:
public class Demo {
    public static void main(String[] args) {
        System.out.println("[捡起一把98K]");
        Gun gun = new Kar98K();
        System.out.println("[开炮!]");
        gun.fire();
        System.out.println("[装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[开炮!]");
        gun.fire();
    }
}

输出:

[捡起一把98K]
[开炮!]
砰*5
[装饰上弹匣]
[开炮!]
砰*10

现在我要装上4倍镜,使它具有4倍瞄准功能,这是枪支原本没有的功能。

扩展枪支接口功能:

public interface Aim4X extends Gun {
    public void aim4X();
}

public abstract class AbstractTelescope4X implements Aim4X {
    private Gun gun;

    public AbstractTelescope4X(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Telescope4X extends AbstractTelescope4X {
    public Telescope4X(Gun gun) {
        super(gun);
    }

    @Override
    public void aim4X() {
        System.out.println("已进入4倍瞄准模式");
    }
}

/** * 55式4倍镜 */
public class Telescope4X55 extends AbstractTelescope4X {
    public Telescope4X55(Gun gun) {
        super(gun);
    }

    @Override
    public void aim4X() {
        System.out.println("4倍超级瞄准已部署");
    }
}

测试:

public class Demo {
    public static void main(String[] args) {
        System.out.println("[捡起一把98K]");
        Gun gun = new Kar98K();
        System.out.println("[装饰上4倍镜]");
        Aim4X aim4X = new Telescope4X(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
        System.out.println("[先装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[再装饰上4倍镜]");
        aim4X = new Telescope4X(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
        System.out.println("[人体描边?换上我的55式4倍镜]");
        aim4X = new Telescope4X55(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
    }
}

输出:

[捡起一把98K]
[装饰上4倍镜]
[4倍瞄准]
已进入4倍瞄准模式
[开炮!]
砰*5
[先装饰上弹匣]
[再装饰上4倍镜]
[4倍瞄准]
已进入4倍瞄准模式
[开炮!]
砰*10
[人体描边?换上我的55式4倍镜]
[4倍瞄准]
4倍超级瞄准已部署
[开炮!]
砰*10

现在我要装上8倍镜,它具有4倍瞄准功能,也具有8倍瞄准功能。

扩展接口:

public interface Aim8X extends Aim4X {
    public void aim8X();
}

public abstract class AbstractTelescope8X implements Aim8X {
    private Gun gun;

    public AbstractTelescope8X(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Telescope8X extends AbstractTelescope8X {
    public Telescope8X(Gun gun) {
        super(gun);
    }

    @Override
    public void aim8X() {
        System.out.println("进入8倍瞄准模式");
    }

    @Override
    public void aim4X() {
        System.out.println("进入4倍瞄准模式");
    }
}

测试:

public class Demo {
    public static void main(String[] args) {
        System.out.println("[先装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[再装饰上8倍镜]");
        aim8X = new Telescope8X(gun);
        System.out.println("[8倍瞄准]");
        aim8X.aim8X();
        System.out.println("[敌人很近,换4倍]");
        aim8X.aim4X();
        System.out.println("[开炮!]");
        aim8X.fire();
    }
}

输出:

[先装饰上弹匣]
[再装饰上8倍镜]
[8倍瞄准]
进入8倍瞄准模式
[敌人很近,换4倍]
进入4倍瞄准模式[开炮!]砰*10

2261装饰器模式

《HeadFirst 设计模式》里的装饰器模式的代码。

package HeadFirst设计模式.装饰者模式_星巴兹订单系统;
 
/**
 *区别于Shape,Beverage采用抽象类
 *通常装饰者模式是采用抽象类,但是在Java中可以使用接口
 */
public abstract class Beverage {
    public String description = "Unknown Beverage";
 
    public String getDescription() {
        return description;
    }
 
    public abstract double cost();
}
package HeadFirst设计模式.装饰者模式_星巴兹订单系统.被装饰者;

import HeadFirst设计模式.装饰者模式_星巴兹订单系统.Beverage;
/**
 *被装饰类继承Beverage抽象类,最终会通过装饰者动态添加上新的行为
 */
public class DarkRoast extends Beverage {

    public DarkRoast() {
        description = "DarkRoast";
    }

    @Override    
    public double cost() {
        return 0.99;
    }
}
package HeadFirst设计模式.装饰者模式_星巴兹订单系统.装饰者;
import HeadFirst设计模式.装饰者模式_星巴兹订单系统.Beverage;

/**
 *这是继承Beverage的抽象装饰者,接下来所有具体的装饰者都要继承CondimentDecorator
 */
public abstract class CondimentDecorator extends Beverage {

    /**     
     *所有的调料装饰者都必须重新实现该方法,因为调料的该方法应该得到扩充,方法实现不同于原来方法     
     */    
    public abstract String getDescription();

}
package HeadFirst设计模式.装饰者模式_星巴兹订单系统.装饰者;

import HeadFirst设计模式.装饰者模式_星巴兹订单系统.Beverage;

/**
 *摩卡,是具体的装饰者
 *用一个实例变量记录饮料(被装饰者)
 *装饰者和被装饰者通过组合来增强功能,实现功能的扩展,用组合来替代继承
 */
public class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override    
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }

    @Override    
    public double cost() {
        return 0.20 + beverage.cost();
    }
}

测试:

package HeadFirst设计模式.装饰者模式_星巴兹订单系统;

import HeadFirst设计模式.装饰者模式_星巴兹订单系统.被装饰者.DarkRoast;
import HeadFirst设计模式.装饰者模式_星巴兹订单系统.装饰者.Mocha;


public class TestStarbuzzCoffee {
    public static void main(String[] args) {
        Beverage beverage1 = new DarkRoast();
        beverage1 = new Mocha(beverage1);
        beverage1 = new Mocha(beverage1);
        System.out.println(beverage1.getDescription()+ " $" + beverage1.cost());
    }
}

输出:

/Library/.../Java/设计模式/bin HeadFirst设计模式.装饰者模式_星巴兹订单系统.TestStarbuzzCoffee
DarkRoast, Mocha, Mocha $1.39

Process finished with exit code 0

2260装饰器模式

游戏里英雄皮肤的实现 是不是也比较适合装饰器模式

public interface Hero {
    public void init();
}

public class victor implements Hero {
    @Override
    public void init() {
        System.out.println("维克托:输出型英雄 武器:步枪");
    }
}

public abstract class HeroDecorator implements Hero {
    private Hero heroDecorator;

    public HeroDecorator(Hero heroDecorator) {
        this.heroDecorator = heroDecorator;
    }

    @Override
    public void init() {
        heroDecorator.init();
    }
}

public class GalacticWarriors extends HeroDecorator {
    private Hero heroDecorator;

    public GalacticWarriors(Hero heroDecorator) {
        super(heroDecorator);
    }

    @Override
    public void init() {
        super.init();
        setSkin();
    }

    private void setSkin() {
        System.out.println("皮肤:银河战士套装");
    }
}

public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Hero victor = new victor();
        GalacticWarriors galacticWarriors = new GalacticWarriors(victor);
        galacticWarriors.init();
    }
}

2259装饰器模式

一个更易理解的实例:

装饰模式为已有类动态附加额外的功能就像LOL、王者荣耀等类Dota游戏中,英雄升级一样。每次英雄升级都会附加一个额外技能点学习技能。具体的英雄就是ConcreteComponent,技能栏就是装饰器Decorator,每个技能就是ConcreteDecorator;

//Component 英雄接口 
public interface Hero {
    //学习技能
    void learnSkills();
}
//ConcreteComponent 具体英雄盲僧
public class BlindMonk implements Hero {
    
    private String name;
    
    public BlindMonk(String name) {
        this.name = name;
    }

    @Override
    public void learnSkills() {
        System.out.println(name + "学习了以上技能!");
    }
}
//Decorator 技能栏
public class Skills implements Hero{
    
    //持有一个英雄对象接口
    private Hero hero;
    
    public Skills(Hero hero) {
        this.hero = hero;
    }

    @Override
    public void learnSkills() {
        if(hero != null)
            hero.learnSkills();
    }    
}
//ConreteDecorator 技能:Q
public class Skill_Q extends Skills{
    
    private String skillName;

    public Skill_Q(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }

    @Override
    public void learnSkills() {
        System.out.println("学习了技能Q:" +skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:W
public class Skill_W extends Skills{

    private String skillName;

    public Skill_W(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }

    @Override
    public void learnSkills() {
        System.out.println("学习了技能W:" + skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:E
public class Skill_E extends Skills{
    
    private String skillName;
    
    public Skill_E(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }

    @Override
    public void learnSkills() {
        System.out.println("学习了技能E:"+skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:R
public class Skill_R extends Skills{    
    
    private String skillName;
    
    public Skill_R(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }
    
    @Override
    public void learnSkills() {
        System.out.println("学习了技能R:" +skillName );
        super.learnSkills();
    }
}
//客户端:召唤师
public class Player {
    public static void main(String[] args) {
        //选择英雄
        Hero hero = new BlindMonk("李青");
        
        Skills skills = new Skills(hero);
        Skills r = new Skill_R(skills,"猛龙摆尾");
        Skills e = new Skill_E(r,"天雷破/摧筋断骨");
        Skills w = new Skill_W(e,"金钟罩/铁布衫");
        Skills q = new Skill_Q(w,"天音波/回音击");
        //学习技能
        q.learnSkills();
    }
}

输出:

学习了技能Q:天音波/回音击
学习了技能W:金钟罩/铁布衫
学习了技能E:天雷破/摧筋断骨
学习了技能R:猛龙摆尾
李青学习了以上技能!