装饰模式 订阅
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 展开全文
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
信息
外文名
Decorator Pattern
类    别
设计模式
又    名
装饰者模式
中文名
装饰模式
设计原则
多用组合,少用继承
装饰模式定义
23种设计模式之一,英文叫Decorator Pattern,又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
收起全文
精华内容
下载资源
问答
  • 装饰模式

    2021-03-06 11:39:36
    装饰模式属于结构型设计模式之一。 在不改变类文件和使用继承的前提下,动态地扩展一个对象的功能。 是继承的替代方案之一。它是通过创建一个包装对象,来装饰包裹真实的对象。 定义 动态地扩展对象功能,比生成子类...

    介绍

    装饰模式属于结构型设计模式之一。 在不改变类文件和使用继承的前提下,动态地扩展一个对象的功能。 是继承的替代方案之一。它是通过创建一个包装对象,来装饰包裹真实的对象。

    定义

    动态地扩展对象功能,比生成子类更为灵活。

    类图

    在这里插入图片描述

    示例

    装饰模式在现实生活中有很多例子,比如给一个人穿上各种衣服,给一幅画涂色上框等等,这次我要举得例子有些不同,举一个武侠修炼武功的例子:杨过本身就会全真剑法,有两位武学前辈洪七公和欧阳锋分别传授杨过打狗棒法和蛤蟆功,这样杨过除了会全真剑法还会打狗棒法和蛤蟆功。

    抽象组件(Component)
    作为武侠肯定要会使用武功的,我们先定义一个武侠的抽象类,里面有使用武功的抽象方法:

    public abstract class Swordsman {
        /**     
        * Swordsman武侠有使用武功的抽象方法     
        */
        public abstract void attackMagic();
    }
    

    组件具体实现类(ConcreteComponent)
    被装饰的具体对象,在这里就是被教授武学的具体的武侠,他就是杨过,杨过作为武侠当然也会武学,虽然不怎么厉害:

    public class YangGuo extends Swordsman{
        
        public void attackMagic() {
            //杨过初始的武学是全真剑法
            System.out.println("杨过使用全真剑法");
        }
    }
    
    

    抽象装饰者(Decorator)
    抽象装饰者保持了一个对抽象组件的引用,方便调用被装饰对象中的方法。在这个例子中就是武学前辈要持有武侠的引用,方便教授他武学并“融会贯通”:

    public abstract class Master extends Swordsman{
        private Swordsman mSwordsman;
    
        public Master(Swordsman mSwordsman){
            this.mSwordsman=mSwordsman;
        }
        
        public void attackMagic() {
            mSwordsman.attackMagic();
        }
    }
    

    装饰者具体实现类(ConcreteDecorator)
    这个例子中用两个装饰者具体实现类,分别是洪七公和欧阳锋,他们负责来传授杨过新的武功:

    public class HongQiGong extends Master {
        public HongQiGong(Swordsman mSwordsman) {
            super(mSwordsman);
        }
        public void teachAttackMagic(){
            System.out.println("洪七公教授打狗棒法");
            System.out.println("杨过使用打狗棒法");
        }
        
        public void attackMagic() {
            super.attackMagic();
            teachAttackMagic();
        }
    }
    public class OuYangFeng extends Master {
        public OuYangFeng(Swordsman mSwordsman) {
            super(mSwordsman);
        }
        public void teachAttackMagic(){
            System.out.println("欧阳锋教授蛤蟆功");
            System.out.println("杨过使用蛤蟆功");
        }
        
        public void attackMagic() {
            super.attackMagic();
            teachAttackMagic();
        }
    }
    

    客户端调用
    经过洪七公和欧阳锋的教导,杨过除了初始武学全真剑法又学会了打狗棒法和蛤蟆功:

    public class Client {
        public static void main(String[] args){
            //创建杨过
            YangGuo mYangGuo=new YangGuo();
            //洪七公教授杨过打狗棒法,杨过会了打狗棒法
            HongQiGong mHongQiGong=new HongQiGong(mYangGuo);
            mHongQiGong.attackMagic();
    
            //欧阳锋教授杨过蛤蟆功,杨过学会了蛤蟆功
            OuYangFeng mOuYangFeng=new OuYangFeng(mYangGuo);
            mOuYangFeng.attackMagic();
        }
    }
    

    优点

    通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
    有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
    具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

    缺点

    装饰链不能过长,否则会影响效率。
    因为所有对象都是继承于Component,所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者),如果基类改变,势必影响对象的内部。
    比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐,所以只在必要的时候使用装饰者模式。

    使用场景

    在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
    需要动态地给一个对象增加功能,这些功能可以动态的撤销。
    当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    装饰模式和代理模式

    代理模式和装饰模式有点像,都是持有了被代理或者被装饰对象的引用。它们两个最大的不同就是装饰模式对引用的对象增加了功能,而代理模式只是对引用对象进行了控制却没有对引用对象本身增加功能。

    展开全文
  • 装饰模式 – 半透明装饰模式: 目录 I/O 应用 源码: 输入流 InputStream 应用: 读取txt文件: 结果: Poi读取excel文件: 读取excel代码: 测试: 结果: 总结: 在装饰模式的学习中,会出现一个透明...

    装饰模式 – 半透明装饰模式:

     目录

    I/O 应用

    源码:

    输入流 InputStream

    应用:

    读取txt文件:

    结果:

    Poi读取excel文件:

    读取excel代码:

    测试:

    结果:

    总结:


     在装饰模式的学习中,会出现一个透明装饰模式和半透明的装饰,是什么意思呢?

     

    透明装饰模式

     在透明装饰模式中要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。对客户端而言,具体构件类和具体装饰类对象没有任何区别。(缺点,无法单独调用装饰类的独有功能)

    比如在例子中:都是用 ShapeDecorator 去声明要装饰的内容

     

    半透明装饰模式

       用具体装饰类型来定义装饰后的对象,而具体构件类型仍然可以使用抽象构件类型来定义,可以单独调用装饰的独有方法。(缺点:无法多次进行装饰)

     

       是否透明,是根据装饰的对象是否根据抽象对象来定义去判断的。 半透明是运用具体的装饰类来声明,而非抽象类去声明。

     

    I/O 应用

    装饰模式在Java语言中的最典型的应用是Java I/O标准库的设计

      由于Java I/O库需要很多性能的各种组合,如果这些性能都是用继承的方法实现的,那么每一种组合都需要一个类,这样就会造成大量性能重复的类出现。而如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最少。因此装饰模式是Java I/O库的基本模式。

      Java I/O库的对象结构图如下,由于Java I/O的对象众多,因此只显示InputStream部分的内容。

    https://img2018.cnblogs.com/blog/163758/201811/163758-20181130134239124-1398707803.png

      根据上图可以看出:

      ●  抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。

      ●  具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、ObjectInputStream, FilterInputStream等类扮演。它们实现了抽象构件角色所规定的接口。

     

    源码:

     

    输入流 InputStream

    public abstract class InputStream implements Closeable {
        private static final int MAX_SKIP_BUFFER_SIZE = 2048;
    
        public abstract int read() throws IOException;
    
        public int read(byte b[]) throws IOException {
            return read(b, 0, b.length);
        }
    
        public int read(byte b[], int off, int len) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if (off < 0 || len < 0 || len > b.length - off) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
    
            int c = read();
            if (c == -1) {
                return -1;
            }
            b[off] = (byte)c;
    
            int i = 1;
            try {
                for (; i < len ; i++) {
                    c = read();
                    if (c == -1) {
                        break;
                    }
                    b[off + i] = (byte)c;
                }
            } catch (IOException ee) {
            }
            return i;
        }
    
        public long skip(long n) throws IOException {
    
            long remaining = n;
            int nr;
    
            if (n <= 0) {
                return 0;
            }
    
            int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
            byte[] skipBuffer = new byte[size];
            while (remaining > 0) {
                nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
                if (nr < 0) {
                    break;
                }
                remaining -= nr;
            }
    
            return n - remaining;
        }
    
        public int available() throws IOException {
            return 0;
        }
    
        public void close() throws IOException {}
    
        public synchronized void mark(int readlimit) {}
    
        public synchronized void reset() throws IOException {
            throw new IOException("mark/reset not supported");
        }
    
        public boolean markSupported() {
            return false;
        }
    }
    

    FileInputStream 的源码,添加了自己的一些方法,这意味着,其变成了半透明的装饰类

     

    应用:

    读取txt文件:

    public class ReadTxtTest {
    
        public static void main(String[] args) throws IOException {
            String filePath="E:/yan.txt";
            // 流式读取文件
            DataInputStream dis = null;
            try{
                dis = new DataInputStream(
                        new BufferedInputStream(
                                new FileInputStream(filePath)
                        )
                );
                //读取文件内容
                byte[] bs = new byte[dis.available()];
                dis.read(bs);
                String content = new String(bs);
                System.out.println(content);
            }catch (Exception e){
                e.getMessage();
            }finally{
                dis.close();
            }
    
        }
    }

     

    结果:

    岁月因温良而静好,时光因唯美而温馨。生命,因有你而丰盈,尘世,因你我执手而深情。若你回眸,菩提花开,何须繁华,何须盛装,你就是那抹最亮的光华,照亮我这一世前行的方向。

    人生,有春也有秋,有暖自有寒,心灵的恬淡,缘于灵魂深处的爱。爱是所有坚持的理由,纵有千般磨难,亦是甜蜜的负担。生活里总是有太多压力,要么它把你压倒,要么你把它举起。爱是力量,也是希望,更是经年所有坚守的信念。爱,不必等待,因为生命的每一天都在悄无声息的流逝,轻盈而安静。爱,不必徘徊,因为它是你这一世发自内心的笃定。

     

    poi读取excel文件

     

    总结:

        理解是否透明,主要是理解是否全使用抽象对象去声明对象。I/O操作,在工作中也常用,需要熟练使用。

     

    展开全文
  • 设计模式 | 装饰模式

    2021-03-26 09:24:17
    1 | 装饰模式的概述 我们在了解装饰模式之前,先回顾下生活中的几个常见现象,举例如下: 新房的装修,房屋装修并没有改变房屋居住的本质,但可以让房屋变得更漂亮,更温馨,更实用,更满足居家需求。 相片的包装...

    1 | 装饰模式的概述

    我们在了解装饰模式之前,先回顾下生活中的几个常见现象,举例如下:

    • 新房的装修,房屋装修并没有改变房屋居住的本质,但可以让房屋变得更漂亮,更温馨,更实用,更满足居家需求。
    • 相片的包装,照相馆中把原相片清洗出来后,会对上面做些包装/装饰,相片镀膜,添加相框等处理,让整体更加美观,防潮保存更长的时间。

    在软件设计中,类似上面的场景我们也可以把对象在不改变结构的情况下对其加工扩展修饰,使得对象具有更加强大的功能,这种技术在设计模式中就叫装饰模式。装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。

    1.1 装饰模式的定义

    • 装饰模式:动态地给一个对象增加一些额外的职责。就扩展功能面言,装饰模式提供了—种比使用子类更加灵活的替代方案。
    • Decorator Pattern:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

    装饰模式是一种对象结构型模式,它以对客户透明的方式动态地给一个对象附加上更多的责任,可以在不需要创建更多子类的情况下,让对象的功能得以扩展。

    装饰模式是一种用于替代继承的技术,它通过一开无须定义子类的方式给对象动态增加职责,使用对象之间的关联天系取代类之间的继承关系。装饰模式降低了系统的耦合度。可以动态增加或删除对象的职责,并使得需要装饰的具体构件类和用于装饰的具体装饰类都可以独立变化,增加新的具体构件类和具体装饰类都非常方便,符合开闭原则。

    2 | 装饰模式的结构与实现

    2.1 装饰模式的结构

    类图结构

    装饰模式包含以下 4 个角色

    • (1) Componcnt(抽象构件),它是具体构件和抽象装饰类的共同父奥,声明了在具体构件中实轰的业备方法,它的引入可以使客户湖以一致的方式处理未被装饰的对象以及装饰之后的对象,字现客户端的透明操作。
    • (2) ConcreteComponent(具体钩件),它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象物件中声明的方法,装饰类可以给它增加额外的职责(方法)。
    • (3) Decorater(抽象装饰类),它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责通常在其子类中实舰,它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子面扩展该方法,以达到装饰的目的。
    • (4) ConcreteDecorator(具体装饰类),它是抽象装饰类的子类,负责向构件添加新的职责,每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并且可以增加新的方法,以实现扩展对象的行为。

    2.2 装饰模式的实现

    【抽象构件类/Component】一般设计为抽象类或者接口,在其中声明了抽象业务方法,当然,也可以在抽象构件类中实现一些所有具体构件类都共有的业务方法。抽象构件类的典型代码如下:

    abstract class Component
    {
        public abstract void Operation();
    }

    【具体构件类/ConcreteComponent 】作为抽象构件类的子类实现了在抽象构件类中声明的业务方法,通常在具体构件类中只提供基本功能的实现,一些复杂的功能需通过装饰类来进行扩展,其典型代码如下:

    class ConcreteComponent : Component
    {
        public override void Operation()
        {
            Console.WriteLine("基本功能实现");
        }
    }

    【抽象装饰类/Decorator 】装饰模式的核心在于装饰类的设计,其典型代码如下:

    class Decorator : Component
    {
        private readonly Component _Component;  //维持一个对抽象构件对象的引用
    
        //注入一个抽象构件类型的对象
        public Decorator(Component component)
        {
            _Component = component;
        }
    
        public override void Operation()
        {
            _Component.Operation();  //调用原有业务方法
        }
    }

    【具体装饰类/ConcreteDecorator】是抽象装饰类的子类,可以根据需要对父类方法 Operation() 进行扩展,典型代码如下:

    class ConcreteDecorator : Decorator 
    {
        public ConcreteDecorator(Component component) : base(component)
        {
    	}
    
    	public override void Operation() 
        {
    		base.Operation();  //调用原有业务方法
    		AddedBehavior();  //调用新增业务方法
    	}
    
        //新增业务方法
    	public void AddedBehavior() 
        {	
            Console.WriteLine("功能扩展实现");
        }
    }

    在具体装饰类中可以调用抽象装饰类的 Operation() 方法,同时可以定义新的业务方法,例如 AddedBehavior() ,如果该方法不希望客户端单独调用,还可以将其可访问性修改为私有(private)。

    客户端调用

    3 | 装饰模式的应用实例

    3.1 实例说明

    某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent。该构件库提供了大量的基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,如带滚动条的窗体、带黑色边框的文本框,既带滚动条又带黑色边框的列表框等,因此经常需要对该构件库进行扩展以增强其功能,现使用装饰模式来设计该图形界面构件库。

    3.2 实例代码设计

    类图结构

    示例代码说明

    • VisualComponent :抽象界面构件类,充当抽象构建类。
    • Window、TextBox、ListBox :VisualComponent 的派生类,充当具体构建类。
    • ComponentDecorator :VisualComponent 的派生类,充当抽象装饰器类。
    • BlackBorderDecorator、ScrollBarDecorator :ComponentDecorator 的派生类,充当具体装饰类。

    客户端调用

    如果需要在原系统中增加一个新的具体构建类或者新的具体装饰类,无须修改现有的类库代码,只需将他们分别作为抽象构建类或者抽象装饰类的子类即可。

    完整代码示例请查看 =》https://gitee.com/dolayout/DesignPatternOfCSharp/tree/master/DesignPatternOfCSharp/DecoratorPattern

    4 | 透明装饰模式与半透明装饰模式

    在装饰模式中,具体装饰类通过新增成员变量或者成员方法来扩展具体构建类的功能。

    • 在标准的装饰模式中,新增行为需要在原有的业务方法中调用,无论是具体构建对象还是装饰过后的构建对象,对于客户端而言都是透明的,这种装饰模式被称为透明(Transparent)装饰模式
    • 但是在某些情况下,有些新增行为可能需要单独被调用,此时,客户端不能再一致性地处理装饰之前的对象和装饰之后的对象,这种装饰模式被称为半透明(Semi-transparent)装饰模式

    下面将对这两种装饰模式进行较为详细的介绍。

    4.1 透明装饰模式

    在透明装饰模式中,要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。对于客户端而言,具体构件对象和具体装饰对象没有任何区别。即应该使用以下代码:

    Component component = new ConcreteComponent(); //推荐:使用抽象构件类型定义对象
    //ConcreteComponent component = new ConcreteComponent(); //不推荐:使用具体构件类型定义对象
    
    Decorator decorator = new ConcreteDecorator(component); //推荐:抽象装饰器类型定义对象
    //ConcreteDecorator decorator = new ConcreteDecorator(component); //不推荐:具体装饰器类型定义对象

    对于多次装饰而言,在客户端中存在以下代码片段:

    Component component_o, component_d1, component_d2; //全部使用抽象构件定义
    component_o = new ConcreteComponent();
    component_d1 = new ConcreteDecoratoz1(component_o);
    component_d2 = new ConcreteDecorator2(component_d1);
    component_d2.Operation();
    //无法单独调用 component_d2 的 AddedBehavior() 方法

    使用抽象构件类型 Component 定义全部具体构件对象和具体装饰对象,客户端可以一致地使用这此对象,因此符合透明装饰模式的要求。
    透明装饰模式可以让客户端透明地使用装饰之前的对象和装饰之后的对象,无须关心它们的区别,此外,还可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象,在实现透明装饰模式时,要求具体装饰类的 Operation() 方法覆盖抽象装饰类的 Operation() 方法,除了调用原有对象的 Operation() 外还需要调用新增的 AddedBehavior() 方法来增加新行为。但是由于在抽象构件中并没有声明 AddedBehavior() 方法,因此,无法在客户端单独调用该方法,上面的图形界面构件库的设计方案中使用的就是透明装饰模式。

    4.2 半透明装饰模式

    透明装饰模式的设计难度较大,而且有时需要单独调用新增的业务方法,为了能够调用到新增的方法,不得不用具体的装饰类来定义装饰后的对象,而具体构件可以继续使用抽象对象构件类型来定义,这种装饰模式即为半透明装饰模式。

    客户端调用

    1. 具体构件类型无须关心,是透明的,使用抽象构建类型定义;
    2. 具体装饰类型必须指定,是不透明的,使用具体装饰类型定义;

    客户端示例代码片段如下:

    Component component = new ConcreteComponent(); //使用抽象构建类型定义
    ConcreteDecorator decorator = new ConcreteDecorator(component); //使用具体装饰类型定义
    decorator.Operation(); //调用单独的新增业务方法

    半透明装饰模式可以给系统带来更多的灵活性,设计相对简单,使用起来也非常方便;但是其最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象。在实现半透明的装饰模式时,只需在具体装饰类中增加一个独立的 AddedBehavior() 方法来封装相应的业务处理即可,由于客户端使用具体装饰类型来定义装饰后的对象,因此可以单独调用 AddedBehavior() 方法。

    5 | 装饰模式的优缺点与适用环境

    装饰模式降低了系统的耦合度,可以动态增加或删除对象的职责,并使得需要装饰的具体构件类和用于装饰的具体装饰类可以独立变化,以便增加新的且休构件米和且体装饰类。使用装饰模式将大大减少子类的个数,让系统扩展起来更加方俑,而日更灾具维护,是取代继承复用的有效方式之一。在软件开发中,装饰模式得到了较为广泛的应用。

    5.1 装饰模式的优点

    • (1)对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加。
    • (2)装饰模式可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。
    • (3)装饰模式可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。
    • (4)在装饰模式中,具体构件类与具体装饰类是可以独立变化的,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无须改变,符合开闭原则。

    5.2 装饰模式的缺点

    • (1)使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能。
    • (2)装饰模式提供了一种比继承更加灵活机动的解决方案,但同时也意味着比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

    5.3 装饰模式的适用环境

    • (1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
    • (2)当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。

    不能采用继承的情况主要有两种:

    1. 第一种是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;
    2. 第二种是因为类已定义为不能被继承(例如 C# 语言中的密封类,即使用 sealed 关键字修饰的类);
    展开全文
  • 最近看了刘伟老师的设计模式史上最全设计模式导学目录(完整版)_刘伟技术博客-CSDN博客学习了里面的状态模式,做一下后面的练习题。处理对象的多种状态及其相互转换——状态模式(六)_刘伟技术博客-CSDN博客 ...

    最近看了刘伟老师的设计模式史上最全设计模式导学目录(完整版)_刘伟技术博客-CSDN博客学习了里面的状态模式,做一下后面的练习题。处理对象的多种状态及其相互转换——状态模式(六)_刘伟技术博客-CSDN博客

    练习

           Sunny软件公司欲开发一款纸牌游戏软件,在该游戏软件中用户角色具有入门级(Primary)、熟练级(Secondary)、高手级(Professional)和骨灰级(Final)四种等级,角色的等级与其积分相对应,游戏胜利将增加积分,失败则扣除积分。入门级具有最基本的游戏功能play() ,熟练级增加了游戏胜利积分加倍功能doubleScore(),高手级在熟练级基础上再增加换牌功能changeCards(),骨灰级在高手级基础上再增加偷看他人的牌功能peekCards()。

           试使用状态模式来设计该系统。

     首先说一下什么是状态模式:

    状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

     然后分析问题,首先有用户对象,用户可以有多个等级,不同等级有不同的功能,用户等级是根据用户积分来确定的,并且下一个等级是在上一个等级基础上增加一定的功能,。 这里针对不同的等级还可以使用装饰模式来实现。这里来说一下装饰模式的概述

    装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

    扩展系统功能——装饰模式(二)_刘伟技术博客-CSDN博客

    我们先定义状态接口,状态接口有三个方法,玩游戏方法play, 加分方法addScore,减分方法reduceScore:

    package com.pattern.state.practice;
    
    public interface CardState {
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param winningProbability  胜率,
         * @return 结果 true 赢,false 输,
         */
        boolean play(Double winningProbability);
    
        /**
         * 加分
         * @param cardGame
         * @param score
         */
        void addScore(PlayerGame cardGame, double score);
    
        /**
         * 减分
         * @param cardGame
         * @param score
         */
        void reduceScore(PlayerGame cardGame, double score);
    }
    

    然后创建用户对象:

    package com.pattern.state.practice;
    
    public class PlayerGame {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public PlayerGame(String name, double score) {
            this.name = name;
            System.out.println("玩家" + name + "准备开始!");
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
            this.addScore(score);
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         */
        public void play(double amount){
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(name + "赢了!");
               currencyState.addScore(this, amount);
            }else {
                //输了减分
                System.out.println(name + "输了!");
                currencyState.reduceScore(this, amount);
            }
        }
    
        public void addScore(Double addScore){
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            //设置状态
            setState();
            System.out.println("当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
        private void setState(){
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
    }

    然后创建状态类,入门级,熟练级,高手级,骨灰级,状态之间从低到高依次继承上一级。类图表示为:

     入门级:

    package com.pattern.state.practice;
    
    
    /**
     * 入门级
     */
    public class PrimaryState implements CardState{
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * @param winningProbability  胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            double random =  Math.random();
            if (random <= winningProbability){
                return true;
            }
            return false;
        }
    
        @Override
        public void addScore(PlayerGame cardGame, double score) {
            cardGame.addScore(score);
        }
    
        @Override
        public void reduceScore(PlayerGame cardGame, double score) {
            cardGame.addScore(-score);
        }
    }
    

     熟练级:

    package com.pattern.state.practice;
    
    /**
     * 熟练级,特有功能赢了积分加倍。
     * 重新addScore方法,加倍积分
     */
    public class SecondaryState extends PrimaryState{
        /**
         * 启用积分加倍功能
         * @param cardGame
         * @param score
         */
        @Override
        public void addScore(PlayerGame cardGame, double score) {
            score = doubleScore(score);
            System.out.println("启用积分加倍功能!加倍积分:" + score);
            super.addScore(cardGame, score);
        }
    
        /**
         * 积分加倍功能
         * @param score
         * @return
         */
        private double doubleScore(double score){
            return score * 2;
        }
    }
    

    高手级:

    package com.pattern.state.practice;
    
    /**
     * 高手级,增加换牌功能。 增加换牌功能后胜率会提升
     */
    public class ProfessionalState extends SecondaryState{
    
    
        /**
         * 这里用装饰模式实现各种技能。
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = changeCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 增加换牌功能,胜率增加, 增加幅度控制在0到0.1之间
         * @param winningProbability
         * @return
         */
        private double changeCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/10;
            System.out.println("使用换牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    
    }
    

    骨灰级:

    package com.pattern.state.practice;
    
    /**
     * 骨灰级,增加看牌功能
     */
    public class FinalState extends ProfessionalState{
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         *
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = peekCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 看牌功能, 胜率增加  增加范围是 0 到 0.2
         * @param winningProbability
         * @return
         */
        private double peekCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/5;
            System.out.println("使用看牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    }
    

    然后测试一下:

    package com.pattern.state.practice;
    
    public class Client {
        public static void main(String[] args) {
            PlayerGame cardGame = new PlayerGame("赌神", 500);
            for (int i = 0; i < 100; i++) {
                cardGame.play(100);
            }
        }
    }
    

    运行结果为:

    玩家赌神准备开始!
    当前分数为:500.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5916589286277115
    赌神输了!
    当前分数为:400.0 当前级别为:SecondaryState
    赌神输了!
    当前分数为:300.0 当前级别为:SecondaryState
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:500.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.555551350633584
    赌神输了!
    当前分数为:400.0 当前级别为:SecondaryState
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:600.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5450863977166052
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:800.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5449084037248595
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:1000.0 当前级别为:FinalState
    使用看牌功能,胜率增加!0.5324777583421992
    使用换牌功能,胜率增加!0.6043353386294867
    赌神输了!

     思考:实际游戏中,游戏会有多种多样的,玩家也是不同的。如果玩家玩其他游戏,这个模式就不能用了。这里在针对PlayerGame把玩家,和游戏拆分出来,用桥接模式来完成。

    桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

     这里加一个刘伟老师的桥接模式入口:

    处理多维度变化——桥接模式(一)_刘伟技术博客-CSDN博客

     这样我们把玩家Player,游戏 Game,状态CardState都抽象成接口。

    实例如下:玩家

    package com.pattern.state.practiceup.abs;
    //玩家
    public interface Player {
        void play(double amount);
        Double getScore();
        void setScore(Double score);
        String getName();
        void setName(String name);
        Game getGame();
        void setGame(Game game);
        CardState getCurrencyState();
        void setCurrencyState(CardState currencyState);
    }
    

    游戏:

    package com.pattern.state.practiceup.abs;
    
    /**
     * 游戏,
     */
    public interface Game {
        /**
         * 玩游戏
         * @param amount
         * @param player
         */
        void play(double amount, Player player);
    
        /**
         * 加分数
         * @param addScore
         * @param player
         */
        void addScore(Double addScore, Player player);
    }
    

    状态:

    package com.pattern.state.practiceup.abs;
    
    public interface CardState {
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param winningProbability  胜率,
         * @return 结果 true 赢,false 输,
         */
        boolean play(Double winningProbability);
    
        /**
         * 加分
         * @param cardGame
         * @param player
         * @param score
         */
        void addScore(Game cardGame, Player player, double score);
    
        /**
         * 减分
         * @param cardGame
         * @param player
         * @param score
         */
        void reduceScore(Game cardGame,Player player, double score);
    }
    

    然后针对接口做实现,这样就可以有不同的玩家,玩不同的游戏。

    //斗地主游戏
    public class CardGame implements Game {
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public CardGame() {
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         * @param player
         */
        @Override
        public void play(double amount, Player player){
            CardState currencyState = player.getCurrencyState();
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(player.getName() + "斗地主赢了!");
                currencyState.addScore(this, player, amount);
            }else {
                //输了减分
                System.out.println(player.getName() + "斗地主输了!");
                currencyState.reduceScore(this, player, amount);
            }
        }
    
        @Override
        public void addScore(Double addScore, Player player){
            Double score = player.getScore();
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            CardState currencyState;
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
            player.setCurrencyState(currencyState);
            player.setScore(score);
            System.out.println(player.getName() + "当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
    }

    玩家:

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Game;
    import com.pattern.state.practiceup.abs.Player;
    
    public class PlayerGame implements Player {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private Game game;  //游戏类型。 纸牌,麻将,骨牌,
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
        public PlayerGame(String name, double score, Game game) {
            this.name = name;
            this.game = game;
            game.addScore(score, this);
            System.out.println("玩家" + name + "准备开始!");
        }
        @Override
        public void play(double amount){
            game.play(amount,this);
        }
        @Override
        public Double getScore() {
            return score;
        }
        @Override
        public void setScore(Double score) {
            this.score = score;
        }
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public Game getGame() {
            return game;
        }
        @Override
        public void setGame(Game game) {
            this.game = game;
        }
    }
    

    状态:

    /**
     * 入门级
     */
    public class PrimaryState implements CardState {
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * @param winningProbability  胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            double random =  Math.random();
            if (random <= winningProbability){
                return true;
            }
            return false;
        }
    
        @Override
        public void addScore(Game cardGame, Player player, double score) {
            cardGame.addScore(score, player);
        }
    
        @Override
        public void reduceScore(Game cardGame, Player player, double score) {
            cardGame.addScore(-score, player);
        }
    }
    
    /**
     * 熟练级,特有功能赢了积分加倍。
     * 重新addScore方法,加倍积分
     */
    public class SecondaryState extends PrimaryState {
        /**
         * 启用积分加倍功能
         * @param cardGame
         * @param player
         * @param score
         */
        @Override
        public void addScore(Game cardGame, Player player, double score) {
            score = doubleScore(score);
            System.out.println("启用积分加倍功能!加倍积分:" + score);
            super.addScore(cardGame, player, score);
        }
    
        /**
         * 积分加倍功能
         * @param score
         * @return
         */
        private double doubleScore(double score){
            return score * 2;
        }
    }
    
    /**
     * 高手级,增加换牌功能。 增加换牌功能后胜率会提升
     */
    public class ProfessionalState extends SecondaryState {
    
    
        /**
         * 这里用装饰模式实现各种技能。
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = changeCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 增加换牌功能,胜率增加, 增加幅度控制在0到0.1之间
         * @param winningProbability
         * @return
         */
        private double changeCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/10;
            System.out.println("使用换牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    
    }
    
    /**
     * 骨灰级,增加看牌功能
     */
    public class FinalState extends ProfessionalState {
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         *
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = peekCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 看牌功能, 胜率增加  增加范围是 0 到 0.2
         * @param winningProbability
         * @return
         */
        private double peekCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/5;
            System.out.println("使用看牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    }
    
    

    还可以增加一个打麻将游戏:

    public class MahjongGame implements Game {
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public MahjongGame() {
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         * @param player
         */
        @Override
        public void play(double amount, Player player){
            CardState currencyState = player.getCurrencyState();
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(player.getName() + "打麻将赢了!");
                currencyState.addScore(this, player, amount);
            }else {
                //输了减分
                System.out.println(player.getName() + "打麻将输了!");
                currencyState.reduceScore(this, player, amount);
            }
        }
    
        @Override
        public void addScore(Double addScore, Player player){
            Double score = player.getScore();
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            CardState currencyState;
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
            player.setCurrencyState(currencyState);
            player.setScore(score);
            System.out.println(player.getName() + "当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
    }
    

    测试一下:

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.Game;
    
    public class Client {
        public static void main(String[] args) {
            //Game game = new CardGame();
            Game game = new MahjongGame();
            PlayerGame cardGame = new PlayerGame("赌神", 500, game);
            for (int i = 0; i < 100; i++) {
                cardGame.play(100);
            }
        }
    }
    

    总结:设计模式就是把事务里面固定的东西拿出来,忽略细节,好的设计会让程序更优雅。

    再思考一下,玩游戏过程中有可能会输光所有的积分可以用备忘录模式在输光之后返回上一次的状态重新玩。

    备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。

     我们创建一个备忘录对象GameMemento:

    package com.pattern.state.practiceup;
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Player;
    /**
     * 游戏备忘录
     */
    public class GameMemento {
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        public GameMemento(Player player) {
            this.score = player.getScore();
            this.currencyState = player.getCurrencyState();
        }
        public Double getScore() {
            return score;
        }
        public void setScore(Double score) {
            this.score = score;
        }
        public CardState getCurrencyState() {
            return currencyState;
        }
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    }

    再创建一个备忘录责任人对象Caretaker:

    package com.pattern.state.practiceup;
    /**
     * 备忘录责任人
     */
    public class Caretaker {
        private GameMemento memento;
        public GameMemento getMemento() {
            return memento;
        }
        public void setMemento(GameMemento memento) {
            this.memento = memento;
        }
    }
    

    由Player玩家作为原发器, 在Player里面添加一个创建备忘录的方法createMemento();和一个恢复方法restorMemento(GameMemento memento);

    package com.pattern.state.practiceup.abs;
    
    import com.pattern.state.practiceup.GameMemento;
    
    public interface Player {
        void play(double amount);
        Double getScore();
        void setScore(Double score);
        String getName();
        void setName(String name);
        Game getGame();
        void setGame(Game game);
        CardState getCurrencyState();
        void setCurrencyState(CardState currencyState);
        GameMemento createMemento();
        void restorMemento(GameMemento memento);
    
    }

     再由子类实现这两个方法

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Game;
    import com.pattern.state.practiceup.abs.Player;
    
    public class PlayerGame implements Player {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private Game game;  //游戏类型。 纸牌,麻将,骨牌,
        //这里也可以让玩家持有 备忘录责任人
        //private Caretaker caretaker = new Caretaker();
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
        @Override
        public GameMemento createMemento() {
            return new GameMemento(this);
        }
    
        /*@Override
        public void restorMemento() {
            GameMemento memento = caretaker.getMemento();
            this.score = memento.getScore();
            this.currencyState = memento.getCurrencyState();
        } */
        @Override
        public void restorMemento(GameMemento memento) {
            this.score = memento.getScore();
            this.currencyState = memento.getCurrencyState();
        }
        public PlayerGame(String name, double score, Game game) {
            this.name = name;
            this.game = game;
            game.addScore(score, this);
            System.out.println("玩家" + name + "准备开始!");
        }
        @Override
        public void play(double amount){
            //caretaker.setMemento(createMemento());
            game.play(amount,this);
        }
        @Override
        public Double getScore() {
            return score;
        }
        @Override
        public void setScore(Double score) {
            this.score = score;
        }
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public Game getGame() {
            return game;
        }
        @Override
        public void setGame(Game game) {
            this.game = game;
        }
    }
    
    

    然后测试一下,为了模拟输光的场景,这里吧游戏的获胜概率给调低。MahjongGame.winningProbability=0.1;

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.Game;
    
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args) {
            //Game game = new CardGame();
            Game game = new MahjongGame();
            Caretaker caretaker = new Caretaker();
            PlayerGame cardGame = new PlayerGame("赌神", 500, game);
            for (int i = 0; i < 100; i++) {
                caretaker.setMemento(cardGame.createMemento());
                cardGame.play(100);
                Double score = cardGame.getScore();
                if(score < 0){
                    System.out.println("分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出");
                    Scanner in = new Scanner(System.in);
                    String command = in.next();
                    if("Y".equalsIgnoreCase(command)){
                        //cardGame.restorMemento();
                        System.out.println("充值成功!");
                        cardGame.restorMemento(caretaker.getMemento());
                    }else{
                        System.out.println(cardGame.getName() + "已破产!游戏结束");
                        break;
                    }
                }
            }
        }
    }
    

     运行结果:

    赌神当前分数为:500.0 当前级别为:ProfessionalState
    玩家赌神准备开始!
    使用换牌功能,胜率增加!0.13414493470770883
    赌神打麻将输了!
    赌神当前分数为:400.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:300.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:200.0 当前级别为:SecondaryState
    赌神打麻将赢了!
    启用积分加倍功能!加倍积分:200.0
    赌神当前分数为:400.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:300.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:200.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:100.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:0.0 当前级别为:PrimaryState
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    t
    赌神已破产!游戏结束

    这样游戏就达到了赚钱的目的。实现盈利。

     最后来一个总的类图

     

    展开全文
  • 装饰模式(Decorator):装饰模式可以在不修改对象外观和功能的情况下添加或者删除对象功能。它可以使用一种对客户端来说透明的方法来修改对象的功能,也就是使用初始类的子类实例对初始对象进行授权。装饰模式还为...
  • 装饰模式概念:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活(大话设计模式)在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也...
  • Java 的 IO 系统采用了装饰器设计模式。其 IO 分为面向字节和面向字符两种,面向字节以字节为输入输出单位,面向字符以字符为输入输出单位。此外,在每部分中,又分为输入和输出两部分,相互对应,如InputStream类型...
  • 模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制,使用继承机制是给现有...装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不
  • 本篇讲解装饰模式,和组合模式一样分成两种类型,一个是透明装饰模式,一个是不透明装饰模式,仔细观察的人可能会发现好像两个的类图有点相像,但是说实话两个思想却是相差很远,我个人觉得如果你是学会模式的内在...
  • php 装饰模式

    2021-06-01 10:32:25
    某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,...请使用装饰模式来设计该图形界面构件库。 类图: ...
  • 装饰模式
  • 装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方法来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。装饰模式降低了系统的耦合度,可以动态增加或删除对象的职责,
  • 适配器模式 结构 目标抽象类(定义目标服务所需要的接口,) 适配器类(是一个转换器,对目标接口和适配者进行适配) 适配者类(目标服务需要的业务方法) 简单示例 例:某公司开发一款玩具汽车,玩具汽车支持在...
  • 设计模式之装饰模式

    2021-03-25 15:11:49
    装饰模式 装饰模式(Decorator Pattern)是一种比较常见的模式,动态地给一个对象添加一些额外的职责。不改变原有对象动态扩展,可替代继承但是多层装饰会导致复杂化。 假设我们现在有个奶茶店,我们制作奶茶,假如...
  • 01. 装饰模式1. 定义Decorator装饰器,就是动态地给一个对象添加一些额外的职责,动态扩展,和下面继承(静态扩展)的比较。因此,装饰器模式具有如下的特征:它必须持有一个被装饰的对象(作为成员变量)。它必须拥有与...
  • 目录一、前言二、装饰模式三、实际例子四、结构与参与者五、简单的示例代码六、总结 一、前言 装饰(Decorator)模式主要是在组合(Composite)模式的基础上扩展,因此并不为其专门开一次研讨会,在闲余时间自行学习...
  • java模式之装饰模式

    2021-03-03 11:24:47
    关 键 词:Java模式阅读提示:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。说明:装饰模式是在不必改变原类文件和使用继承...
  • 装饰模式与代理模式

    2021-09-06 14:11:01
    文章目录一、装饰模式1、装饰模式的定义2、装饰模式结构图3、装饰模式总结二、代理模式1、代理模式的定义2、代理模式结构图 一、装饰模式 1、装饰模式的定义 “动态地给对象添加一些额外的职责,就增加功能来说,...
  • Decorator 装饰模式 设计模式学习:概述 意图 动态地给一个对象添加一些额外的职责,就增加功能来说,Decorator模式相比生成子类更为灵活。 Decorator(装饰模式)也被称作Wrapper(包装器)。 Decorator模式是对...
  • 这里很重要的一点是是比继承更有弹性,根据翻译的不同,装饰模式也有人称之为“油漆工模式”。 why为什么需要装饰模式 首先介绍一下常见的给一个类或者对象增加行爲的方式: 继承,使用继承机制是给现有类...
  • 实验七 装饰模式的应用(Java实现) 一、实验目的 掌握装饰模式(Decorator)的特点 分析具体问题,使用装饰模式进行设计。 二、实验内容和要求 “喜羊羊逃命”游戏:喜羊羊被灰太狼追,喜羊羊最多5条命,灰太狼每咬...
  • 由上述的例子可以看出来,如果T50Tank想要获得红外线和水陆两栖的功能,就要继承4个父类,这就导致了由于过多使用继承来扩展对象的功能,所以采用装饰模式来对代码进行修改。 思想: 继承是静态的,我们要实现动态...
  • 系列总链接:https://blog.csdn.net/qq_22122811/article/details/112360387 ... ... 一:概述 装饰模式(Decorator,有些地方或称作Wrapper):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成.
  • 装饰模式 A:说明 其他模式虽然也存在职责问题,但装饰模式在责任划分这块是极其突出的模式之一。另一是桥模式。 B:例子(有关io操作) 实现一个对文件流/网络流/内存流,进行加密/缓存/加密缓存操作。UML和代码...
  • 咖啡馆与装饰模式

    2021-12-13 19:36:06
    咖啡馆与装饰模式需求思考装饰模式的定义代码样例原材料基类然后扩展一些我们会用到的原材料最后,我们来生产咖啡吧总结 需求 楼下的咖啡馆要开业了,我们看看他们主营的产品有哪些: 热牛奶 高乐高 摩卡 卡布奇诺 ...
  • 说明:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。装饰模式的特点;(1) 装饰对象和真实对象有相同的接口。这样客户端对象...
  • 1、装饰模式(Decorator):动态地给一个对象天剑一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。装饰模式是以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。动态方式给一个对象附加更...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 143,831
精华内容 57,532
关键字:

装饰模式

友情链接: ztz.zip