《大话设计模式》简读
来源:互联网 发布:java字符串转换整形 编辑:程序博客网 时间:2024/06/11 13:47
感谢《大话设计模式》作者程杰
简单工厂模式
客户端不关心对象如何创建, 只需知道传入工厂类的参数
计算器–面向对象–可维护、可复用、可扩展–业务与界面分离–业务分离(继承)
/** * Operation 父类 * 抽象类 用于代表实现类 * @author xmd * */abstract class Operation{ public double NumberA; public double NumberB; public abstract double GetResult();}class OperationAdd extends Operation{ @Override public double GetResult() { return NumberA + NumberB; } }class OperationSub extends Operation{ @Override public double GetResult() { return NumberA - NumberB; } }class OperationMul extends Operation{ @Override public double GetResult() { return NumberA * NumberB; } }class OperationDiv extends Operation{ @Override public double GetResult() { if(NumberB == 0){ throw new RuntimeException("除数为0"); } return NumberA / NumberB; } }/** * 简单工厂 * 根据运算符号生成相应的实现类 * @author xmd * */class OperationFactory { public static Operation createOperation(String operate){ Operation opre = null; switch (operate) { case "+": opre = new OperationAdd(); break; case "-": opre = new OperationSub(); break; case "*": opre = new OperationMul(); break; case "/": opre = new OperationDiv(); break; } return opre; }}/** * 计算界面 * @author xmd * */public class Jiandangongchang { public static void main(String[] args) { Operation oper; oper = OperationFactory.createOperation("+"); oper.NumberA=15; oper.NumberB=2; System.out.println(oper.GetResult()); }}
策略模式
封装算法,封装规则,应用 于不同时间不同业务规则
让算法的变化,不会影响到使用算法的客户
商场收银
/** * 抽象算法类 * @author xmd * */abstract class Strategy{ //算法方法 public abstract void AlgorithmInterface();}class ConcreteStrategyA extends Strategy{ @Override public void AlgorithmInterface() { System.out.println("算法A实现"); }}class ConcreteStrategyB extends Strategy{ @Override public void AlgorithmInterface() { System.out.println("算法B实现"); }}class ConcreteStrategyC extends Strategy{ @Override public void AlgorithmInterface() { System.out.println("算法C实现"); }}/** * 上下文 维护对Strategy对象的引用 配置ConcreteStrategy * @author xmd * */class Context{ Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void ContextInterface(){ strategy.AlgorithmInterface(); }}/** * 策略模式: * 通过Context组合Strategy成员对象, * 传入Context适当的Strategy成员对象, * 调用对应Strategy对象的algorithmInterface()。 * @author xmd * */public class celue { public static void main(String[] args) { Context context; //根据要求选择策略 可用简单工厂模式 实现选择方案 context = new Context(new ConcreteStrategyA()); context.ContextInterface(); context = new Context(new ConcreteStrategyB()); context.ContextInterface(); context = new Context(new ConcreteStrategyC()); context.ContextInterface(); }}
装饰模式
当某个对象的职责经常发生变化或者需要动态的增加职责
穿着
/** * 定义一个对象接口,可以给这些对象动态的添加职责 * @author xmd * */abstract class Component{ public abstract void Opration();}/** * 定义一个具体的对象,也可以给这个对象添加职责 * @author xmd * */class ConcreteComponent extends Component{ @Override public void Opration() { System.out.println("被装饰的具体对象"); }}/** * 装饰抽象类, 从外类扩展Component的功能,但对于Component来说,是无需知道Decorate的存在 * @author xmd * */class Decorator extends Component{ protected Component component; /** *实际执行Component的Opration() */ @Override public void Opration() { if(component != null){ component.Opration(); } } public void setComponent(Component component) { this.component = component; }}/** * 具体的装饰对象,起到给Component添加职责 * @author xmd * */class ConcreteDecoratorA extends Decorator{ private String addedState; @Override public void Opration() { super.Opration(); addedState = "new State"; System.out.println("具体装饰对象A的操作"); }}/** * 具体的装饰对象,起到给Component添加职责 * @author xmd * */class ConcreteDecoratorB extends Decorator{ @Override public void Opration() { super.Opration(); AddedBehacior(); System.out.println("具体装饰对象A的操作"); } private void AddedBehacior() { System.out.println("具体装饰对象B独有方法"); }}public class zhuangshi { public static void main(String[] args) { ConcreteComponent component = new ConcreteComponent(); ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(); ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(); concreteDecoratorA.setComponent(component);//为component装饰A concreteDecoratorB.setComponent(concreteDecoratorA);//为component装饰A后再装饰B concreteDecoratorB.Opration(); }}
代理模式
为其他对象提供一种代理以控制对这个对象的访问。隐藏真实访问对象,同时可以处理别的事情
/** * 定义了RealSubject和Proxy共用的接口 * @author xmd * */abstract class Subject{ public abstract void Request();}/** * 真实类 * @author xmd * */class RealSubject extends Subject{ @Override public void Request() { System.out.println("真实的请求"); }}class Proxy extends Subject{ private RealSubject realSubject; @Override public void Request() { if(realSubject == null) realSubject = new RealSubject(); realSubject.Request(); }}public class daili { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.Request(); }}
工厂方法
克服了简单工厂模式违背开闭原则,又保持了封装对象创建过程的优点。一个类想要由自己的子类来定义某对象的创建过程。
雷锋
/** * 雷锋 * @author xmd * */class LeiFeng{ public void Sweep(){ System.out.println("扫地"); } public void Wash(){ System.out.println("洗衣"); }}/** * 学习雷锋学生 * @author xmd * */class Undergraduate extends LeiFeng{}/** * 学习雷锋志愿者 * @author xmd * */class Volunteer extends LeiFeng{}/** * 工厂接口 * @author xmd * */interface Factory { public LeiFeng createLeiFeng();}/** * 工厂实现类 具体实现学生 * @author xmd * */class GraduateFactory implements Factory{ @Override public LeiFeng createLeiFeng() { return new Undergraduate(); }}/** * 工厂实现类 具体实现学生 * @author xmd * */class VolunteerFactory implements Factory{ @Override public LeiFeng createLeiFeng() { return new Volunteer(); }}public class gongchangfangfa { public static void main(String[] args) { Factory factory = new GraduateFactory(); Undergraduate student = (Undergraduate) factory.createLeiFeng(); student.Sweep(); Factory VFactory = new VolunteerFactory(); Volunteer volunteer = (Volunteer) VFactory.createLeiFeng(); volunteer.Sweep(); }}
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。简化对象的创建过程,隐藏了对象创建的细节,又对性能大大的提高。频繁使用一个对象,比如在循环体中
/** * 原型类 * 一个类重写了 Object 内定义的 clone() ,需要同时实现 Cloneable 接口 * 如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException。 * (1)浅克隆(shallow clone),浅拷贝是指拷贝对象时仅仅拷贝对象本身和对象中的基本变量,而不拷贝对象包含的引用指向的对象。 *(2)深克隆(deep clone),深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。 * @author xmd * */abstract class Prototype implements Cloneable{ private String id; public Prototype(String id) { this.id = id; } public String getId() { return id; } public abstract Prototype Clone() throws CloneNotSupportedException;}/** * 具体原型类 * @author xmd * */class ConcretePrototype extends Prototype{ public ConcretePrototype(String id) { super(id); } @Override public Prototype Clone() throws CloneNotSupportedException { return (Prototype) this.clone(); }}public class yuanxing { public static void main(String[] args) throws CloneNotSupportedException { ConcretePrototype cPrototype1 = new ConcretePrototype("1"); ConcretePrototype cPrototype2 = (ConcretePrototype) cPrototype1.Clone(); System.out.println(cPrototype1.getId()); System.out.println(cPrototype2.getId()); }}
模板方法
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类不改变算法的结构,即可重定义该算法的某些特定步骤。把不变行为搬移到超类,去除子类中的重复代码,体现它的优势。通过父类调用子类,这是一种反向的控制
学生抄写考试题
/** * 父类 包含了公共方法 * @author xmd * */abstract class AbstractClass{ public abstract void PrimitveOperation1(); public abstract void PrimitveOperation2(); public void TemplateMethod(){ PrimitveOperation1(); PrimitveOperation2(); }}class ConcreteClassA extends AbstractClass{ @Override public void PrimitveOperation1() { System.out.println("A类方法1实现"); } @Override public void PrimitveOperation2() { System.out.println("A类方法2实现"); }}class ConcreteClassB extends AbstractClass{ @Override public void PrimitveOperation1() { System.out.println("B类方法1实现"); } @Override public void PrimitveOperation2() { System.out.println("B类方法2实现"); }}public class mubanfangfa { public static void main(String[] args) { AbstractClass abstractClass; abstractClass = new ConcreteClassA(); abstractClass.TemplateMethod(); abstractClass = new ConcreteClassB(); abstractClass.TemplateMethod(); }}
外观模式
为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这一接口使得这一子系统更加容易使用。1.减少客户端处理的对象数目2.对客户端屏蔽了子系统, 实现了解耦合
package dhsjms;class SubSystemOne{ public void MethodOne(){ System.out.println("子系统方法一"); }}class SubSystemTwo{ public void MethodTwo(){ System.out.println("子系统方法二"); }}class SubSystemThree{ public void MethodThree(){ System.out.println("子系统方法三"); }}class Facade{ SubSystemOne subSystemOne; SubSystemTwo subSystemTwo; SubSystemThree subSystemThree; public Facade() { subSystemOne = new SubSystemOne(); subSystemTwo = new SubSystemTwo(); subSystemThree = new SubSystemThree(); } public void MethodA(){ System.out.println("方法组A---"); subSystemOne.MethodOne(); subSystemTwo.MethodTwo(); subSystemThree.MethodThree(); } public void MethodB(){ System.out.println("方法组B---"); subSystemOne.MethodOne(); subSystemThree.MethodThree(); }}public class waiguan { public static void main(String[] args) { Facade facade = new Facade(); facade.MethodA(); facade.MethodB(); }}
建造者模式
将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。建造者隐藏了该对象是如何组装的,所以需要改变一个产品的的内部表示,只需要在定义一个新的具体的建造者就可以了
/** * 产品类,由多个部件组成 */class Product{ List<String> parts = new ArrayList<String>(); public void Add(String part){ parts.add(part); } public void Show(){ System.out.println("产品 创建 ----"); for (String psrt:parts) { System.out.println(psrt); } }}/** * 抽象建造这类,确定产品俩个部件A,B组成,并声明一个得到产品 * 建造后结果的方法GetResult() */abstract class Builder{ public abstract void BuidPartA(); public abstract void BuidPartB(); public abstract Product GetResult();}class ConcreteBuilder1 extends Builder{ private Product product = new Product(); @Override public void BuidPartA() { product.Add("部件A"); } @Override public void BuidPartB() { product.Add("部件B"); } @Override public Product GetResult() { return product; }}class ConcreteBuilder2 extends Builder{ private Product product = new Product(); @Override public void BuidPartA() { product.Add("部件X"); } @Override public void BuidPartB() { product.Add("部件Y"); } @Override public Product GetResult() { return product; }}class Director{ public void Construct(Builder builder){ builder.BuidPartA(); builder.BuidPartB(); }}public class jianzaozhe { public static void main(String[] args){ Director director = new Director(); Builder builder1 = new ConcreteBuilder1(); Builder builder2 = new ConcreteBuilder2(); director.Construct(builder1); Product product1 = builder1.GetResult(); product1.Show(); director.Construct(builder2); Product product2 = builder2.GetResult(); product2.Show(); }}
观察者
发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象,同时监听一个主题对象,这个主题对象在状态发生变化时,会通知所有的观察者对象,是它们能够自动更新自己。解除了通知者和具体观察者的耦合,让耦合的双方依赖于抽象,使得各自的变换不会影响到另一方。当一个对象的改变,需要同时改变其他对象的时候,而且它不知道具体有多少对象需要改变
/** * 抽象通知者,把所有观察者对象的引用保存在一个聚类里,每个主题都可以有任何熟量的观察者。 */abstract class Subject{ private List<Observer> observers = new ArrayList<Observer>(); //增加观察者 public void Attach(Observer observer){ observers.add(observer); } //移除观察者 public void Detach(Observer observer){ observers.remove(observer); } //通知 public void Notify(){ for (Observer o:observers) { o.update(); } }}/** * 抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知是更新自己。 */abstract class Observer{ public abstract void update();}/** * 具体通知者,将有关状态存入具体观察者对象 */class ConcreteSubject extends Subject{ //具体被观察者的状态 private String subjectState; public void setSubjectState(String subjectState) { this.subjectState = subjectState; } public String getSubjectState() { return subjectState; }}class ConcreteObserver extends Observer{ private String name; private String observerState; private ConcreteSubject subject; public ConcreteObserver(String name, ConcreteSubject subject) { this.name = name; this.subject = subject; } @Override public void update() { observerState = subject.getSubjectState(); System.out.println("观察者的最新状态是:"+name+observerState); } public ConcreteSubject getSubject() { return subject; } public void setSubject(ConcreteSubject subject) { this.subject = subject; }}public class guanchazhe { public static void main(String[] args){ ConcreteSubject s = new ConcreteSubject(); s.Attach(new ConcreteObserver("X",s)); s.Attach(new ConcreteObserver("Y",s)); s.Attach(new ConcreteObserver("Z",s)); s.setSubjectState("ABC"); s.Notify(); }}
抽象工厂
提供一个创建一系列相关或相关依赖对象的接口,而无需指定他们具体的类。在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
/*** * 用于客服端访问,解除与具体数据库访问的耦合 */class Department{}interface IDepartment{ void Insert(Department department); Department getDepartment(int id);}class SqlserverDepartment implements IDepartment{ @Override public void Insert(Department department) { System.out.println("Sqlserver insert Department"); } @Override public Department getDepartment(int id) { System.out.println("Sqlserver select Department"); return null; }}class AccessDepartment implements IDepartment{ @Override public void Insert(Department department) { System.out.println("Access insert Department"); } @Override public Department getDepartment(int id) { System.out.println("Access select Department"); return null; }}/** * IFactory接口,定义了一个用来创建Department对象 的 抽象工厂接口 */interface IFactory{ IDepartment CreateDepartment();}class SqlserverFactory implements IFactory{ @Override public IDepartment CreateDepartment() { return new SqlserverDepartment(); }}class AccessFactory implements IFactory{ @Override public IDepartment CreateDepartment() { return new AccessDepartment(); }}public class chouxianggongchang { public static void main(String[] args){ Department department = new Department(); IFactory iFactory = new AccessFactory();//只需更换工厂即可 IDepartment idepartment = iFactory.CreateDepartment(); idepartment.Insert(department); idepartment.getDepartment(2); }}
状态模式
当一个对象的内在状态改变时,允许改变其行为,这个对象看起来改变了其类。消除庞大的条件分支,将特定状态的行为放入一个对象中。通过把各种状态判断逻辑分布到State的子类中,减少相互之间的依赖
/** * 抽象状态 */abstract class State{ public abstract void Hanlde(Context context);}/** * 具体状态1 */class ConcreteStateA extends State{ @Override public void Hanlde(Context context) { context.setState(new ConcreteStateB());//转入新的状态 }}class ConcreteStateB extends State{ @Override public void Hanlde(Context context) { context.setState(new ConcreteStateA()); }}class Context{ private State state; public Context(State state) { this.state = state; } public State getState() { return state; } public void setState(State state) { this.state = state; } public void Request(){ state.Hanlde(this); }}public class zhuangtai { public static void main(String[] args){ Context context = new Context(new ConcreteStateA()); context.Request(); context.Request(); context.Request(); context.Request(); context.Request(); }}
适配器
将一个类的接口转换成客户希望的另一个接口, 使得原本由于接口不兼容不能再一起工作的类,可以在一起工作。通过引入适配器,可以复用现有的类,而不需要修改源代码,将目标类和适配者解耦合,解决了接口和复用环境不一致的情况。
/** * 客户所期待的接口 */class Target{ public void Request(){ System.out.println("普通接口"); }}/** * 需要适配的类 */class Adaptee{ public void SpecificRequest(){ System.out.println("特殊请求"); }}/** * 将源接口转成目标接口 */class Adapter extends Target{ private Adaptee adaptee = new Adaptee(); @Override public void Request() { adaptee.SpecificRequest(); }}public class shipeiqi { public static void main(String[] args){ Target target = new Adapter(); target.Request(); }}
备忘录
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可将对象恢复到保存的状态。把要保存的细节放到备忘录中,当修改保存的信息时,不会影响客户端
/** * 发起类 */class Originator{ private String state; //创建一个备忘录,将当前需要保存的信息导入并new出一个Memento对象 public Memento CreateMenento(){ return new Memento(state); } //恢复数据 public void SetMemento(Memento memento){ state = memento.getState(); } public void Show(){ System.out.println("state" + state); } public String getState() { return state; } public void setState(String state) { this.state = state; }}/** * 备忘录 */class Memento{ private String state; public Memento(String state) { this.state = state; } public String getState() { return state; }}/** * 管理者 */class Caretaker{ private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; }}public class beiwanglu { public static void main(String[] args){ Originator originator = new Originator(); originator.setState("On"); originator.Show(); Caretaker caretaker = new Caretaker(); caretaker.setMemento(originator.CreateMenento()); originator.setState("Off"); originator.Show(); originator.SetMemento(caretaker.getMemento());//恢复 originator.Show(); }}
组合
将对象组合成树形结构,以表示整体-部分的结构, 使得用户对单个对象和组合对象的使用具有一致性。简化客户端代码,在定义组合的那些类中不需要写一些充斥着选择语句的函数。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去
/** * 用于访问和管理Component的子部件 */abstract class Component{ protected String name; public Component(String name) { this.name = name; } public abstract void Add(Component component); public abstract void Remove(Component component); public abstract void Display(int depth);}/** * 叶子节点 */class Leaf extends Component{ public Leaf(String name) { super(name); } @Override public void Add(Component component) { System.out.println("not leaf add"); } @Override public void Remove(Component component) { System.out.println("npt leaf Remove"); } @Override public void Display(int depth) { while(depth>0){ System.out.print("-"); depth--; } System.out.println(name); }}/** * 枝点 */class Composite extends Component{ private List<Component> childrens = new ArrayList<Component>(); public Composite(String name) { super(name); } @Override public void Add(Component component) { childrens.add(component); } @Override public void Remove(Component component) { childrens.remove(component); } @Override public void Display(int depth) { int d = depth; while(d>0){ System.out.print("-"); d--; } System.out.println(name); for (Component component : childrens ) { component.Display(depth+2); } }}public class zuhe { public static void main(String[] args){ Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add(new Leaf("Leaf Xa")); comp.Add(new Leaf("Leaf Xb")); root.Add(comp); Composite comp2 = new Composite("Composite XY"); comp2.Add(new Leaf("Leaf XYa")); comp2.Add(new Leaf("Leaf XYb")); root.Add(comp2); Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); root.Display(1); }}
迭代器
提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示.分离了集合对象的遍历行为,不暴露集合的内部结构,又可让外部访问集合内的数据
/** * Iterator抽象类 */abstract class Iterator{ public abstract Object First(); public abstract Object Next(); public abstract boolean IsDone(); public abstract Object CurrentItem();}abstract class Aggregate{ public abstract Iterator CreateIterator();//创建迭代器}class ConcreteIterator extends Iterator{ private ConcreteAggregate concreteAggregate; private int current=0; public ConcreteIterator(ConcreteAggregate concreteAggregate) { this.concreteAggregate = concreteAggregate; } @Override public Object First() { return concreteAggregate.getObject(0); } @Override public Object Next() { Object ret = null; current++; if(current < concreteAggregate.getCount()){ ret = concreteAggregate.getObject(current); } return ret; } @Override public boolean IsDone() { return current >= concreteAggregate.getCount(); } @Override public Object CurrentItem() { return concreteAggregate.getObject(current); }}class ConcreteAggregate extends Aggregate{ private List<Object> items = new ArrayList<Object>(); @Override public Iterator CreateIterator() { return new ConcreteIterator(this); } public int getCount(){ return items.size(); } public Object getObject(int index){ return items.get(index); } public void setObject(Object object){ items.add(object); }}public class diedaiqi { public static void main(String[] args){ ConcreteAggregate aggregate = new ConcreteAggregate(); aggregate.setObject("一"); aggregate.setObject("二"); aggregate.setObject("四"); aggregate.setObject("三"); aggregate.setObject("七"); aggregate.setObject("九"); aggregate.setObject("八"); Iterator iterator = new ConcreteIterator(aggregate); Object object = iterator.First(); while(!iterator.IsDone()){ System.out.println(iterator.CurrentItem()); iterator.Next(); } }}
单例
保证一个类只有一个实例,并提供一个访问它的全局访问点
class Singleton{ private static Singleton singleton; private Singleton(){} public static Singleton getSingleton(){ if(singleton == null) singleton = new Singleton(); return singleton; }}public class danli { public static void main(String[] args){ Singleton s1 = Singleton.getSingleton(); Singleton s2 = Singleton.getSingleton(); if(s1 == s2){ System.out.println("=="); } }}
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立的变化。1.类和类继承关系会保持较小的规模,不太可能增长为庞然大物。2.使得抽象之间可以独立的变化,起到了解耦合的作用。使用场景: 一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
abstract class Implementor{ public abstract void Operation();}class ConcreteImplementorA extends Implementor{ @Override public void Operation() { System.out.println("Impl A"); }}class ConcreteImplementorB extends Implementor{ @Override public void Operation() { System.out.println("Impl B"); }}class Abstraction{ protected Implementor implementor; public void setImplementor(Implementor implementor) { this.implementor = implementor; } public void Operation(){ implementor.Operation(); }}class RefinedAbstraction extends Abstraction{ @Override public void Operation() { implementor.Operation(); }}public class qiaojie { public static void main(String[] args){ Abstraction abstraction = new RefinedAbstraction(); abstraction.setImplementor(new ConcreteImplementorA()); abstraction.Operation(); abstraction.setImplementor(new ConcreteImplementorB()); abstraction.Operation(); }}
阅读全文
0 0
- 《大话设计模式》简读
- 《大话设计模式》
- 大话设计模式 笔记
- 《大话设计模式》笔记
- 改装:大话设计模式
- 大话设计模式摘要
- 大话设计模式 --- 卷首语
- 《大话设计模式》
- 大话设计模式电子版
- 大话设计模式
- 大话设计模式
- 大话设计模式
- 路遇大话设计模式
- 大话设计模式
- 大话设计模式
- 大话设计模式原则
- 大话设计模式笔记
- 《大话设计模式》读书笔记
- TextView的用法
- 图解SQL的JOIN
- Android7.0 6.0 相机拍照,系统裁剪适配问题
- JDK1.8与JDK1.7环境的切换
- 【surrounded-regions】
- 《大话设计模式》简读
- SSH综合项目实战(快递) -- day03 EasyUI之datagrid、收派标准管理、收派员管理
- 关于<param-value>中的classpath和classpath*的零碎总结
- scala创建动态二维数组Array[ArrayBuffer[]]三种写法
- Android 中的消息传递-广播机制
- SSM(十) 项目重构-互联网项目的Maven结构
- JS简单实现点击复制链接的方法
- 《Python编程:从入门到实践》2-9章 笔记
- About the application of lambda and relayCommand