穿什么有这么重要?--装饰模式

news2024/11/24 13:01:14

1.1 穿什么有这么重要?

约会穿什么?
"那要看你想给人家什么印象?是比较年轻,还是比较干练;是比较颓废,还是要比较阳光;也有可能你想给人家一种极其难忘的印象,那穿法又大不一样了!"
"你这话怎么讲?"
"年轻,不妨走点Hip-Hop路线,大T恤、垮裤、球鞋,典型的年轻人装扮。"
"啊,这不是我喜欢的风格,我从来也没这样穿过。"
"那就换一种,所谓干练,就是要有外企高级白领的样,黑西装、黑领带、黑墨镜、黑皮鞋……"
"你这叫白领?我看是社会人。不行不行。"
"哈,来颓废的吧,颓废其实也是一种个性,可以吸引一些喜欢叛逆的女生。一般来说,其标志是:头发可养鸟、胡子能生虫、衬衣没纽扣、香烟加狐臭。"
"这根本就是'肮脏'的代表吗,开什么玩笑。你刚才提到给人家难忘印象,是什么样的穿法?"
"哈,这当然是绝妙的招了,如果你照我说的去做,娇娇想忘都难。"
"快说快说,是什么?"
"大红色披风下一身蓝色紧身衣,胸前一个大大的'S',表明你其实穿的是'小号',还有最重要的是,一定要'内裤外穿'……"
"喂,你拿我寻开心呀,那是'超人'的打扮呀,'S'代表的也不是'Small',是'Super'的意思。"哈,你终于明白了!我其实想表达的意思就是,你完全可以随便一些,平时穿什么,明天还是穿什么,男生嘛,只要干净一些就可以了,关键不在于你穿什么,而在于你人怎么样。对自己都这么没信心,如何追求女孩子?"

1.2 扮靓第一版

package code.chapter6.decorator1;

public class Person {

	private String name;
    public Person(String name) {
        this.name = name;
    }

    public void wearTShirts() {
        System.out.print(" 大T恤");
    }

    public void wearBigTrouser() {
        System.out.print(" 垮裤");
    }

    public void wearSneakers() {
        System.out.print(" 球鞋");
    }

    public void wearSuit() {
        System.out.print(" 西装");
    }

    public void wearTie() {
        System.out.print(" 领带");
    }

    public void wearLeatherShoes() {
        System.out.print(" 皮鞋");
    }

    public void show() {
        System.out.println("装扮的"+name);
    }
}



package code.chapter6.decorator1;

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		Person xc = new Person("小菜");

        System.out.println(" 第一种装扮:");
        xc.wearTShirts();
        xc.wearBigTrouser();
        xc.wearSneakers();
        xc.show();

        System.out.println(" 第二种装扮:");
        xc.wearSuit();
        xc.wearTie();
        xc.wearLeatherShoes();
        xc.show();

		System.out.println();
		System.out.println("**********************************************");

	}
}

现在需要增加超人的装扮。如果改Person类,就违背了开放-封闭原则了,应该把这些服饰都写成了子类就好了。

1.3 扮靓第二版

package code.chapter6.decorator2;

public class Person {

	private String name;
    public Person(String name) {
        this.name = name;
    }

    public void show() {
        System.out.println("装扮的"+name);
    }
}



package code.chapter6.decorator2;

public abstract class Finery {

    public abstract void show();

}



package code.chapter6.decorator2;

public class TShirts extends Finery {

    public void show(){
        System.out.print(" 大T恤");
    }

}



package code.chapter6.decorator2;

public class BigTrouser extends Finery {

    public void show(){
        System.out.print(" 垮裤");
    }

}



package code.chapter6.decorator2;

public class LeatherShoes extends Finery {

    public void show(){
        System.out.print(" 皮鞋");
    }

}



package code.chapter6.decorator2;

public class Sneakers extends Finery {

    public void show(){
        System.out.print(" 球鞋");
    }

}



package code.chapter6.decorator2;

public class Suit extends Finery {

    public void show(){
        System.out.print(" 西装");
    }

}



package code.chapter6.decorator2;

public class Tie extends Finery {

    public void show(){
        System.out.print(" 领带");
    }

}



package code.chapter6.decorator2;

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		Person xc = new Person("小菜");

        System.out.println(" 第一种装扮:");
        Finery dtx = new TShirts();
        Finery kk = new BigTrouser();
        Finery pqx = new Sneakers();

        dtx.show();
        kk.show();
        pqx.show();
        xc.show();

        System.out.println(" 第二种装扮:");
        Finery xz = new Suit();
        Finery ld = new Tie();
        Finery px = new LeatherShoes();

        xz.show();
        ld.show();
        px.show();
        xc.show();

		System.out.println();
		System.out.println("**********************************************");

	}
}

这样写就好比:你光着身子,当着大家的面,先穿T恤,再穿裤子,再穿鞋,仿佛在跳穿衣舞。难道你穿衣服都是在众目睽睽下穿的吗?"
"你的意思是,应该在内部组装完毕,然后再显示出来?这好像是建造者模式呀。"
"不是的,建造者模式要求建造的过程必须是稳定的,而现在我们这个例子,建造过程是不稳定的,比如完全可以内穿西装,外套T恤,再加披风,打上领带,皮鞋外再穿上破球鞋;当然也完全可以只穿条裤衩就算完成。换句话就是说,通过服饰组合出一个有个性的人完全可以有无数种方案,并非固定的。"
"啊,你说得对,其实先后顺序也是有讲究的,如你所说,先穿内裤后穿外裤,这叫凡人,内裤穿到外裤外面,那就是超人了。"
"哈,很会举一反三嘛,那你说该如何办呢?"
"我们需要把所需的功能按正确的顺序串联起来进行控制,这好像很难办哦。"
"不懂就学,其实也没什么稀罕的,这可以用一个非常有意思的设计模式来实现。"

1.4 装饰模式

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

"啊,装饰这词真好,无论衣服、鞋子、领带、披风其实都可以理解为对人的装饰。"

"Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无须知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能[DPE]。"
"来看看基本的代码实现。"

package com.lhx.design.pattern.test;

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		ConcreteComponent c = new ConcreteComponent();
    	ConcreteDecoratorA d1 = new ConcreteDecoratorA();
    	ConcreteDecoratorB d2 = new ConcreteDecoratorB();

    	d1.SetComponent(c);	//首先用d1来包装c
    	d2.SetComponent(d1);//再用有来包装d1
    	d2.Operation();   	//最终执行d2的Operation()


		System.out.println();
		System.out.println("**********************************************");

	}
}

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


//ConcreteComponent类
class ConcreteComponent extends Component {
    
    public void Operation() {
        System.out.println("具体对象的实际操作");
    }

}

//Decorator类
abstract class Decorator extends Component {

    protected Component component;

    //装饰一个Component对象
    public void SetComponent(Component component) {
        this.component = component;
    }

    //重写Operation(),实际调用component的Operation方法
    public void Operation() {
        if (component != null) {
            component.Operation();
        }
    }
}

//ConcreteDecoratorA类
class ConcreteDecoratorA extends Decorator {
    
    private String addedState;//本类独有子段,以区别于ConcreteDecoratorB类

    public void Operation() {
        super.Operation();//首先运行了原有Component的Operation()

        this.addedState = "具体装饰对象A的独有操作";//再执行本类独有功能
        System.out.println(this.addedState);

    }
}

//ConcreteDecoratorB类
class ConcreteDecoratorB extends Decorator {

    public void Operation() {
        super.Operation();//首先运行了原有Component的Operation()
        this.AddedBehavior();//再执行本类独有功能
    }

    //本类独有方法,以区别于ConcreteDecoratorA类
    private void AddedBehavior() { 
    	System.out.println("具体装饰对象B的独有操作");
    }
}




package com.lhx.design.pattern.test;

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		ConcreteComponent c = new ConcreteComponent();
    	ConcreteDecoratorA d1 = new ConcreteDecoratorA();
    	ConcreteDecoratorB d2 = new ConcreteDecoratorB();

    	d1.SetComponent(c);	//首先用d1来包装c
    	d2.SetComponent(d1);//再用有来包装d1
    	d2.Operation();   	//最终执行d2的Operation()


		System.out.println();
		System.out.println("**********************************************");

	}
}

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


//ConcreteComponent类
class ConcreteComponent extends Component {
    
    public void Operation() {
        System.out.println("具体对象的实际操作");
    }

}

//Decorator类
abstract class Decorator extends Component {

    protected Component component;

    //装饰一个Component对象
    public void SetComponent(Component component) {
        this.component = component;
    }

    //重写Operation(),实际调用component的Operation方法
    public void Operation() {
        if (component != null) {
            component.Operation();
        }
    }
}

//ConcreteDecoratorA类
class ConcreteDecoratorA extends Decorator {
    
    private String addedState;//本类独有子段,以区别于ConcreteDecoratorB类

    public void Operation() {
        super.Operation();//首先运行了原有Component的Operation()

        this.addedState = "具体装饰对象A的独有操作";//再执行本类独有功能
        System.out.println(this.addedState);

    }
}

//ConcreteDecoratorB类
class ConcreteDecoratorB extends Decorator {

    public void Operation() {
        super.Operation();//首先运行了原有Component的Operation()
        this.AddedBehavior();//再执行本类独有功能
    }

    //本类独有方法,以区别于ConcreteDecoratorA类
    private void AddedBehavior() { 
    	System.out.println("具体装饰对象B的独有操作");
    }
}




我明白了,原来装饰模式是利用SetComponent来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中[DPE]。用刚才的例子来说就是,我们完全可以先穿外裤,再穿内裤,而不一定要先内后外。


"还有个问题,刚才写的那个例子中'人'类是Component还是ConcreteComponent呢?"
"哈,学习模式要善于变通,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。"
"啊,原来如此。在这里我们就没有必要有Component类了,直接让服饰类Decorator继承人类ConcreteComponent即可。"

1.5 扮靓第三版

package code.chapter6.decorator3;

//人物形象接口
public interface ICharacter {

   public void show();

}



package code.chapter6.decorator3;

//服饰类
public class Finery implements ICharacter {

    protected ICharacter component;

    public void decorate(ICharacter component) {
        this.component=component;
    }

    public void show() {
        if (this.component != null){
            this.component.show();
        }
    }

}



具体服饰类(ConcreteDecorator)

package code.chapter6.decorator3;

public class TShirts extends Finery {

    public void show(){
        
        System.out.print(" 大T恤");

        super.show();

    }

}



package code.chapter6.decorator3;

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		Person xc = new Person("小菜");

        System.out.println(" 第一种装扮:");
        
        Sneakers pqx = new Sneakers();      //生成球鞋实例
        pqx.decorate(xc);                   //球鞋装饰小菜

        BigTrouser kk = new BigTrouser();   //生成垮裤实例
        kk.decorate(pqx);                   //垮裤装饰“有球鞋装饰的小菜”

        TShirts dtx = new TShirts();        //生成T恤实例
        dtx.decorate(kk);                   //T恤装饰“有垮裤球鞋装饰的小菜”

        dtx.show();                         //执行形象展示

        System.out.println(" 第二种装扮:");

        LeatherShoes px = new LeatherShoes();//生成皮鞋实例
        px.decorate(xc);                    //皮鞋装饰小菜
        
        Tie ld = new Tie();                 //生成领带实例
        ld.decorate(px);                    //领带装饰“有皮鞋装饰的小菜”
        
        Suit xz = new Suit();               //生成西装实例
        xz.decorate(ld);                    //西装装饰“有领带皮鞋装饰的小菜”

        xz.show();                          //执行形象展示

        System.out.println(" 第三种装扮:");
        
        Sneakers pqx2 = new Sneakers();     //生成球鞋实例
        pqx2.decorate(xc);                  //球鞋装饰小菜
        
        LeatherShoes px2 = new LeatherShoes();//生成皮鞋实例
        px2.decorate(pqx2);                 //皮鞋装饰“有球鞋装饰的小菜”
        
        BigTrouser kk2 = new BigTrouser();  //生成垮裤实例
        kk2.decorate(px2);                  //垮裤装饰“有皮鞋球鞋装饰的小菜”
        
        Tie ld2 = new Tie();                //生成领带实例
        ld2.decorate(kk2);                  //领带装饰“有垮裤皮鞋球鞋装饰的小菜”

        Strawhat cm2 = new Strawhat();      //生成草帽实例
        cm2.decorate(ld2);                  //草帽装饰“有领带垮裤皮鞋球鞋装饰的小菜”

        cm2.show();                         //执行形象展示

		System.out.println();
		System.out.println("**********************************************");

	}
}

如果我换一种装饰方式,比如说,增加草帽装扮,再重新组合一下服饰?

那就增加一个草帽子类,再修改一下装饰方案就好了。

package code.chapter6.decorator3;

public class Strawhat extends Finery {

    public void show(){
        System.out.print(" 草帽");
        super.show();
    }

}



1.6 商场收银程序再升级

先打8折,再满300返回100,算法可以是下面这样。

增加一个先折扣再返利的算法子类

package com.lhx.design.pattern.decoratorMode;

public class CashReturnRebate extends CashSuper {

    private double moneyRebate = 1d;
    private double moneyCondition = 0d; //返利条件
    private double moneyReturn = 0d;    //返利值

    //先折扣,再返利。初始化时需要折扣参数,再输入返利条件和返利值。
    //比如“先8折,再满300返100”,就是moneyRebate=0.8,moneyCondition=300,moneyReturn=100
    public CashReturnRebate(double moneyRebate,double moneyCondition,double moneyReturn){
        this.moneyRebate = moneyRebate;
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    //先折扣,再返利
    public double acceptCash(double price,int num){
        double result = price * num * this.moneyRebate;
        if (moneyCondition>0 && result >= moneyCondition)
            result = result - Math.floor(result / moneyCondition) * moneyReturn; 
        return result;
    }
    
}
package com.lhx.design.pattern.decoratorMode;


public class CashContext {

    private CashSuper cs;   //声明一个CashSuper对象

    //通过构造方法,传入具体的收费策略
    public CashContext(int cashType){
        switch(cashType){
            case 1:
                cs = new CashNormal();
                break;
            case 2:
                this.cs = new CashRebate(0.8d);
                break;
            case 3:
                this.cs = new CashRebate(0.7d);
                break;
            case 4:
                this.cs = new CashReturn(300d,100d);
                break;
            case 5:
                this.cs = new CashReturnRebate(0.8d,300d,100d);
                break;
        }
    }

    public double getResult(double price,int num){
        //根据收费策略的不同,获得计算结果
        return this.cs.acceptCash(price,num);
    }    
}

新类CashReturnRebate有原来的两个类:CashReturn和CashRebate有大量重复的代码,另外,如果我现在希望增加一个先满300返100,再打折扣的算法,你如何修改呢?再写一个新类吗?如果我们再增加购买送积分、购买抽奖、购买送小礼品等算法,并且有了各种各样的先后组合,你打算怎么处理呢?

1.7 简单工厂+策略+装饰模式实现

你这样是可以实现同样的功能,但与装饰模式比较起来,并不完美。仔细对比观察一下,还有什么东西没有?"

ConcreteComponent类不存在。那它应该是什么呢?

装饰模式有一个重要的优点,把类中的装饰功能从类中搬移去除,这样可以简化原有的类。我们现在的三个算法类,有没有最基础的呢?

CashSuper原来是抽象类,改成普通类,但实现ISale接口。

package com.lhx.design.pattern.decoratorMode.optimizeOne;

public interface ISale {

   public double acceptCash(double price,int num);

}



CashNormal,相当于ConcreteComponent,是最基本的功能实现,也就是单价×数量的原价算法。

package com.lhx.design.pattern.decoratorMode.optimizeOne;

public class CashNormal implements ISale {
    //正常收费,原价返回
    public double acceptCash(double price,int num){
        return price * num; 
    }    
}

另外两个CashSuper的子类算法,都在计算后,再增加一个super.acceptCash(result, 1)返回。

package com.lhx.design.pattern.decoratorMode.optimizeOne;

public class CashRebate extends CashSuper {

    private double moneyRebate = 1d;
    //打折收费。初始化时必需输入折扣率。八折就输入0.8
    public CashRebate(double moneyRebate){
        this.moneyRebate = moneyRebate;
    }

    //计算收费时需要在原价基础上乘以折扣率
    public double acceptCash(double price,int num){
        double result = price * num * this.moneyRebate;
        return super.acceptCash(result,1);
    }
    
}
package com.lhx.design.pattern.decoratorMode.optimizeOne;

public class CashReturn extends CashSuper {

    private double moneyCondition = 0d; //返利条件
    private double moneyReturn = 0d;    //返利值

    //返利收费。初始化时需要输入返利条件和返利值。
    //比如“满300返100”,就是moneyCondition=300,moneyReturn=100
    public CashReturn(double moneyCondition,double moneyReturn){
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    //计算收费时,当达到返利条件,就原价减去返利值
    public double acceptCash(double price,int num){
        double result = price * num;
        if (moneyCondition>0 && result >= moneyCondition)
            result = result - Math.floor(result / moneyCondition) * moneyReturn; 
        return super.acceptCash(result,1);   
    }
    
}


重点在CashContext类,因为涉及组合算法,所以用装饰模式的方式进行包装,这里需要注意包装的顺序,先打折后满多少返多少,与先满多少返多少,再打折会得到完全不同的结果。

package com.lhx.design.pattern.decoratorMode.optimizeOne;

public class CashContext {

    private ISale cs;   //声明一个ISale接口对象

    //通过构造方法,传入具体的收费策略
    public CashContext(int cashType){
        switch(cashType){
            case 1:
                this.cs = new CashNormal();
                break;
            case 2:
                this.cs = new CashRebate(0.8d);
                break;
            case 3:
                this.cs = new CashRebate(0.7d);
                break;
            case 4:
                this.cs = new CashReturn(300d,100d);
                break;
            case 5:
                //先打8折,再满300返100
                CashNormal cn = new CashNormal();
                CashReturn cr1 = new CashReturn(300d,100d); 
                CashRebate cr2 = new CashRebate(0.8d);
                cr1.decorate(cn);   //用满300返100算法包装基本的原价算法
                cr2.decorate(cr1);  //打8折算法装饰满300返100算法
                this.cs = cr2;      //将包装好的算法组合引用传递给cs对象
                break;
            case 6:
                //先满200返50,再打7折
                CashNormal cn2 = new CashNormal();
                CashRebate cr3 = new CashRebate(0.7d);
                CashReturn cr4 = new CashReturn(200d,50d); 
                cr3.decorate(cn2);  //用打7折算法包装基本的原价算法
                cr4.decorate(cr3);  //满200返50算法装饰打7折算法
                this.cs = cr4;      //将包装好的算法组合引用传递给cs对象
                break;
        }
    }

    public double getResult(double price,int num){
        //根据收费策略的不同,获得计算结果
        return this.cs.acceptCash(price,num);
    }    
}
package com.lhx.design.pattern.decoratorMode.optimizeOne;

import java.util.Scanner;

/**
 * 简单工厂+策略+装饰模式实现
 */

public class Test {

	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		int discount = 0; 		//商品折扣模式
		double price = 0d; 		//商品单价
		int num = 0;			//商品购买数量
		double totalPrices = 0d;//当前商品合计费用
		double total = 0d;		//总计所有商品费用
	
		Scanner sc = new Scanner(System.in);

		do {
			System.out.println("商品折扣模式如下:");	
			System.out.println("1.正常收费");	
			System.out.println("2.打八折");	
			System.out.println("3.打七折");	
			System.out.println("4.满300送100");	
			System.out.println("5.先打8折,再满300送100");	
			System.out.println("6.先满200送50,再打7折");	
			System.out.println("请输入商品折扣模式:");	
			discount = Integer.parseInt(sc.nextLine());
			System.out.println("请输入商品单价:");	
			price = Double.parseDouble(sc.nextLine());
			System.out.println("请输入商品数量:");	
			num = Integer.parseInt(sc.nextLine());
			System.out.println();	

			if (price>0 && num>0){
				
				//根据用户输入,将对应的策略对象作为参数传入CashContext对象中
				CashContext cc = new CashContext(discount);
				
				//通过Context的getResult方法的调用,可以得到收取费用的结果
				//让具体算法与客户进行了隔离
				totalPrices = cc.getResult(price,num);
				
				total = total + totalPrices;
				
				System.out.println();	
				System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ totalPrices +"元");	
				System.out.println();
				System.out.println("总计:"+ total+"元");	
				System.out.println();
			}
		}
		while(price>0 && num>0);

		System.out.println();
		System.out.println("**********************************************");

	}
}

客户端算法不变:

结果显示:

单位1000元,数量为1的商品,原需支付1000元,如果选择先8折再满300送100算法的话,就是1000×0.8=800元,满足两个300元,返200元,最终结果是客户只需支付600元。

单位500元,数量为4的商品,原需支付2000元,如果选择先满200送50再7折算法的话,就是2000中有10个200,送10×50=500元,所以2000-500=1500元,再打7折,1500×0.7,最终结果是客户只需支付1050元。

现在无论如何组合算法,哪怕是先打折再返现,再打折再返现,我都只需要更改CashContext类就可以了。目前代码确实做到了开放封闭。设计模式真是好!

1.8 装饰模式总结

"我觉得装饰模式是为已有功能动态地添加更多功能的一种方式。但到底什么时候用它呢?"
"答得很好,问的问题更加好。你起初的设计中,当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,比如用西装或嘻哈服来装饰小菜,但这种做法的问题在于,它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,就像你起初的那个'人'类,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了[DP]。所以就出现了上面那个例子的情况,我可以通过装饰,让你全副武装到牙齿,也可以让你只挂一丝到内裤。"
"就像你所说的,装饰模式的优点是,把类中的装饰功能从类中搬移去除,这样可以简化原有的类。像前面的原价算法就是最基础的类,而打折或返现,都算是装饰算法了。"
"是的,这样做更大的好处就是有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。我们不必去重复编写类似打折后再返现,或返现后再打折的代码,对于装饰模式来说,只是多几种组合而已。"
"这个模式真不错,我以后要记着常使用它。"
"你可要当心哦,装饰模式的装饰顺序很重要哦,比如加密数据和过滤词汇都可以是数据持久化前的装饰功能,但若先加密了数据再用过滤功能就会出问题了,最理想的情况,是保证装饰类之间彼此独立,这样它们就可以以任意的顺序进行组合了。"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1563983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法错题本

这里写目录标题 错题本注意数据的耦合性对于无解情况的处理思路一组数据以0为结束标记,如何输入到数组中,并计数多个数据进行比较链表删除重复元素的启发循环体里谨慎写类型定义并初始化(一般写上就是错)队列中读取队尾元素数组当…

基于ssm的三省学堂-学习辅助系统(java项目+文档+源码)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的三省学堂-学习辅助系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 三省学堂-学习辅助系统的…

深入理解数据结构第二弹——二叉树(2)——堆排序及其时间复杂度

看这篇前请先把我上一篇了解一下:深入理解数据结构第一弹——二叉树(1)——堆-CSDN博客 前言: 相信很多学习数据结构的人,都会遇到一种情况,就是明明最一开始学习就学习了时间复杂度,但是在后期…

回顾快速排序

快速排序 快速排序的核心: 找到一个key 通常左边的数比key小,右边的数比key大。 找key通常有三种方法: 1. 挖坑法: 代码实现: // int _pivot(int* a, int left, int right) {int begin left, end right;int in…

开源AGV调度系统OpenTCS中的任务分派器(dispatcher)详解

OpenTCS中的任务分派器dispatcher详解 1. 引言2. 任务分派器(dispatcher)2.1 默认的停车位置选择2.2 可选停车位置属性2.3 默认的充电位置选择2.4 即时运输订单分配 3. 默认任务分派器的配置项4. 参考资料与源码 1. 引言 openTCS是一项著名的开源运输控制系统,我在…

Go 源码之 Chan

Go 源码之 chan go源码之chan - Jxy 博客 目录 Go 源码之 chan一、总结二、源码(一)hchan(二)创建(三)发送(四)接收(五)关闭 三、常见问题1.为什么要使用环形…

[Linux] 排查问题指令top/ps/netstat

在Linux下查看某个端口运行的指令 1. 首先通过netstat来查看端口对应的进程号 比如抓取端口53这个DNS服务的进程 netstat -tulnp | grep 53 可以看到53这个端口号对应的pid是720 2. 通过ps指令来对进程号执行的命令查询 ps aux | grep 720 可以看到pid为720这个进程对应的执…

Android APP代码混淆技术解析与实战指南

Android APP 加固是优化 APK 安全性的一种方法,常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆,使得反编译出来的代码很难阅读和理解&#xff…

【中文视觉语言模型+本地部署 】23.08 阿里Qwen-VL:能对图片理解、定位物体、读取文字的视觉语言模型 (推理最低12G显存+)

项目主页:https://github.com/QwenLM/Qwen-VL 通义前问网页在线使用——(文本问答,图片理解,文档解析):https://tongyi.aliyun.com/qianwen/ 论文v3. : 一个全能的视觉语言模型 23.10 Qwen-VL: A Versatile…

CentOS7安装Flink1.17伪分布式

前提条件 拥有1台CentOS7 CentOS7安装好jdk,官方文档要求java 11,使用java 8也可以。可参考 CentOS7安装jdk8 下载安装包 下载安装包 [hadoopnode1 ~]$ cd installfile/ [hadoopnode1 installfile]$ wget https://archive.apache.org/dist/flink/flin…

Stream流,线程

文章目录 Stream流思想作用三类方法获取方法单列集合(Collection[List,Set双列集合Map(不能直接获取)数组同一类型元素(Stream中的静态方法) 常见的中间方法终结方法收集方法 Optional类 线程相关概念多线程概念实现方式继承Thread类实现Runnable接口比较 常用方法线程安全产生…

【现代控制】倒立摆模型

基础公式 转动惯量: 欧拉拉格朗日等式 倒立摆模型建立 由拉格朗日等式推导出微分方程: 也就是 将zdot移到等式左边,化简得到 展开就是: 系统线性化 法一:雅可比矩阵 法二:小角度假设 化简最终得…

nslookup查询网站是否支持IPV6

nslookup是一种网络管理命令行工具,可用于查询DNS域名和IP地址输入指令nslookup默认服务器和Address是当前上网所用的DNS服务器域名和地址A记录A(Address)记录指的是用来指定主机名或域名对应的IP记录。

OpenHarmony实战:轻量级系统之子系统移植概述

OpenHarmony系统功能按照“系统 > 子系统 > 部件”逐级展开,支持根据实际需求裁剪某些非必要的部件,本文以部分子系统、部件为例进行介绍。若想使用OpenHarmony系统的能力,需要对相应子系统进行适配。 OpenHarmony芯片适配常见子系统列…

2024春招冲刺题单 ONT68 最接近的三数之和【中等 数组,递归 Java,Go,PHP】

题目 题目链接: https://www.nowcoder.com/practice/f889497fd1134af5af9de60b4d13af23 相同题目: https://www.lintcode.com/problem/59 思路 本题答案是n数之和相关问题的模板。参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法…

【C语言】“vid”Microsoft Visual Studio安装及应用(检验内存泄露)

文章目录 前言安装包获取配置VLD完成 前言 我们在写代码时往往容易存在内存泄漏的情况,所以存在这样一个名为VLD的工具用来检验内存泄漏,现在我来教大家安装一下 安装包获取 vld下载网址:https://github.com/KindDragon/vld/releases/tag/…

【GPT5进展】GPT-5将于今年年中发布

OpenAI即将发布的GPT-5代表了人工智能技术的一个重大进步,这一新一代模型预计将进一步扩大OpenAI在AI应用领域的影响力。以下是关于GPT-5的几个关键点,旨在清晰、简洁地向读者传达这一重要更新: 1. 性能和功能的实质性提升 GPT-5在性能上做…

读取信息boot.bin和xclbin命令

bootgen读Boot.bin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ bootgen -read BOOT-k26-starter-kit-202305_2022.2.bin xclbinutil读xclbin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ xclbinutil -i kv260-smartca…

2024 年每个程序员都应该尝试的 8 个AI工具

随着人工智能技术的极速发展,新的 AI 工具正以前所未有的速度涌现,为开发者们带来了前所未有的机会和挑战。在这个不断演进的时代,掌握最新的 AI 技术已成为每个程序员的必修课。 在本文中,我们收集了8 个程序员在 2024 年值得尝…

函数调用实现小米汽车智能语音助手

上周小米汽车发布,其中有一个特色功能就是智能语音,小爱同学整合了语音大模型,实现智能座舱体验。 雷老板的PPT也演示了,一些口语化的对话就能触发各种指令,无论是开空调、播放音乐,还是找手机、识别前方汽…