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

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来包装cd2.SetComponent(d1);//再用有来包装d1d2.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来包装cd2.SetComponent(d1);//再用有来包装d1d2.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=100public 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.8public 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=100public 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返100CashNormal 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.mzph.cn/news/788124.shtml

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

相关文章

10秒钟用python接入讯飞星火API(保姆级)

正文: 科大讯飞是中国领先的人工智能公众公司,其讯飞星火API为开发者提供了丰富的接口和服务,以支持各种语音和语言技术的应用。 步骤一:注册账号并创建应用 首先,您需要访问科大讯飞开放平台官网,注册一个…

谷歌google广告和必应Bing广告,是否二选一?

搜索引擎广告凭借其精准定向、高度可见性和高效转化能力,成为众多企业拓展海外市场、提升品牌影响力的重要手段。其中,谷歌Google与必应Bing作为全球两大主流搜索引擎,各自拥有庞大的用户群体与独特的市场优势。面对这两大广告平台&#xff0…

非关系型数据库(缓存数据库)redis的高可用(持久化)

目录 1.redis的高可用 2.Redis持久化 1.Redis 提供两种方式进行持久化 2.RDB持久化 2.1触发条件 2.1.1手动触发 2.1.2自动触发 2.1.3其他自动触发机制 2.2执行流程 ​编辑 2.3 启动时加载 3.AOF持久化 3.1开启AOF 3.2 执行流程 3.2.1append——命令追加 3.…

Crossmanager 2024 64 bit(CAD文件格式转换工具)安装包分享

新增功能 1、NavisWorks输入:首次发布,支持2016至2023版本 2、Fusion 360输入:首次发布,支持版本2.0 3、Catia V6/3D体验输入:支持R2023x版本 4、Solidworks输入:支持Solidworks 2023版本 5、Solid Ed…

《QT实用小工具·八》数据库通用翻页类

1、概述 源码放在文章末尾 该项目实现数据库通用翻页类,主要包含如下功能: 1:自动按照设定的每页多少行数据分页 2:只需要传入表名/字段集合/每页行数/翻页指示按钮/文字指示标签 3:提供公共静态方法绑定字段数据到下拉框 4:建议条件字段用数字类型的主…

机器学习 | 线性判别分析(Linear Discriminant Analysis)

1 机器学习中的建模 1.1 描述性建模 以方便的形式给出数据的主要特征,实质上是对数据的概括,以便在大量的或有噪声的数据中仍能观察到重要特征。重在认识数据的主要概貌,理解数据的重要特征。 Task:聚类分析,数据降…

C++类和对象第三讲总结

1.对象指针:指针->成员 // 指针存放了对象的地址 // 指针作为函数参数,可以真正改变对象成员的值 // 指针可以指向对象数组,它存放了数组首元素地址 // 指针偏移量可以访问数组的每个对象 2.一个练习案例 使用指针和对象数组打印…

【数学公式大全整理——1.0】

导数公式 积分表 万能公式 初等函数 重要极限 ### 诱导公式 和差角 和差化积 倍角公式 半角公式 正弦 余弦定理 反三角函数 高阶求导公式

数据库系统概论(超详解!!!) 第三节 关系数据库标准语言SQL(Ⅳ)

1.集合查询 集合操作的种类 并操作UNION 交操作INTERSECT 差操作EXCEPT 参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同 查询计算机科学系的学生及年龄不大于19岁的学生。SELECT *FROM StudentWHERE Sdept CSUNIONSELECT *FROM StudentWHERE Sage&l…

Kubernetes(k8s):部署、使用 metrics-server

Kubernetes(k8s):部署、使用 metrics-server 一、metrics-server简介二、部署metrics-server2.1、 下载 Metrics Server 部署文件2.2、修改metrics-server.yaml 文件2.3、 部署 Metrics Server2.4、 检查 Metrics Server 三、使用 Metrics Se…

网络升级固件

资源信息 可知 : install\soc_cv1800b_milkv_duo_sd\boot.sd文件较设备中的同名文件多了128个字节的文件头;install\soc_cv1800b_milkv_duo_sd\rawimages\boot.sd文件与设备中同名文件相同; 环境搭建 服务器 启动TFTP服务 安装TFTP服务器…

windows下通过vscode访问ubuntu(绝大部分Linux下开发所采用的方案)

前言 本篇博客是介绍VSCode远程连接Ubuntu进行开发的解决方案,前提是安装好了VMWare,Ubuntu,windows下的VSCode。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关…

深信服:借助观测云实现全链路可观测性

导读 深信服科技股份有限公司 简称「深信服」( Sangfor Technologies Inc. ),是一家领先的网络安全和云计算解决方案提供商,致力于为全球客户提供高效、智能、安全的网络和云服务。随着公司业务的不断扩展,也面临着监…

OpenHarmony实战:轻量系统芯片移植准备

由于OpenHarmony工程需要在Linux环境下进行编译,此章节将指导厂商搭建OpenHarmony的编译环境、获取OpenHarmony源码,并且创建厂商工作目录完成厂商芯片的编译框架适配。 搭建编译环境 开展移植前请参考开发环境准备完成环境搭建工作。 获取源码 获取…

【Redis】Redis的类型及相关操作

一、常用的key操作命令 keys * 查看当前数据库的键值 ttl key 查看还有多少秒过期,-1表示永不过期,-2表示过期 del / unlink key 同样是删除,unlink是非阻塞删除,del则有可能导致阻塞 select dbindex 切换数据库 flushdb 清空…

群晖配置FTP服务结合内网穿透实现公网访问本地NAS中储存文件

文章目录 1. 群晖安装Cpolar2. 创建FTP公网地址3. 开启群晖FTP服务4. 群晖FTP远程连接5. 固定FTP公网地址6. 固定FTP地址连接 本文主要介绍如何在群晖NAS中开启FTP服务并结合cpolar内网穿透工具,实现使用固定公网地址远程访问群晖FTP服务实现文件上传下载。 Cpolar内…

文章分享:《呼吸道传染病标本采集及检测专家共识》

【摘要】呼吸道传染病临床特点多表现为发热和(或)呼吸道症状,病原学组成复杂,标本类型选择多样,如何从发热伴呼吸道症候群患者中早期正确识别出潜在呼吸道传染病患者是防控的关键环节。增强医务人员对呼吸道传染病临床…

unity学习(78)--unity调试--长痛不如短痛

1.在vs2022中,工具--获取工具与功能。 2. 安装图中工具,原来我早就安装了。 3 f9下断 同时点击图中按钮 vs此时变为如下状态 unity中出现如下提示: 4 在unity中运行游戏,vs这边确实成功断住了!

第四百三十七回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 们在上一章回中介绍了"不同平台上换行的问题"相关的内容,本章回中将介绍如何在页面上显示蒙板层.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们…

【已解决】java: 无效的目标发行版: 19

问题描述 现在从Spring Boot官网下载的Spring boot文件的诸多配置的版本,无法直接选择和电脑已有配置相匹配的。所以直接下载安装包,并用IDEA打开后无法直接运行。 我在网站上下载的配置如下图: 我遇到的问题是运行时报错java: 无效的目标发…