结构型模式-适配器模式

维基百科 适配器模式 在设计模式中,适配器模式(英语:adapter pattern)有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类能在一起工作,做法是将类自己的接口包裹在一个已存在的类中。 结构 有两种类型的适配器模式: 对象适配器模式 在这种适配器模式中,适配器容纳一个它包裹的类的实例。在这种情况下,适配器调用被包裹对象的物理实体。 类适配器模式 这种适配器模式下,适配器继承自已实现的类(一般多重继承)。 例子 Target 定义Client使用的与特定领域相关的接口。 public interface Target { void adapteeMethod(); void adapterMethod(); } Adaptee 定义一个已经存在的接口,这个接口需要适配。 public class Adaptee { public void adapteeMethod(){ System.out.println("Adaptee method"); } } Adapter 对Adaptee的接口与Target接口进行适配 public class Adapter implements Target{ private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee=adaptee; } @Override public void adapteeMethod() { adaptee.adapteeMethod(); } @Override public void adapterMethod() { System.out.println("Adapter method"); } } Client 与符合Target接口的对象协同。 public class Test { public static void main(String[] args) { Target target = new Adapter(new Adaptee()); target.adapteeMethod(); target.adapterMethod(); } } 运行结果: ...

August 24, 2019 · 1 min · zhangxiaofeng05

创建型模式-原型模式

维基百科 原型模式 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。 Java /** Prototype Class **/ public class Cookie implements Cloneable { public Object clone() throws CloneNotSupportedException { //In an actual implementation of this pattern you would now attach references to //the expensive to produce parts from the copies that are held inside the prototype. return (Cookie) super.clone(); } } /** Concrete Prototypes to clone **/ public class CoconutCookie extends Cookie { } /** Client Class**/ public class CookieMachine { private Cookie cookie;//cookie必须是可复制的 public CookieMachine(Cookie cookie) { this.cookie = cookie; } public Cookie makeCookie() { try { return (Cookie) cookie.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } public static void main(String args[]){ Cookie tempCookie = null; Cookie prot = new CoconutCookie(); CookieMachine cm = new CookieMachine(prot); //设置原型 for(int i=0; i<100; i++) tempCookie = cm.makeCookie();//通过复制原型返回多个cookie } } 例子 Prototype 声明一个克隆自身的接口 ...

August 24, 2019 · 2 min · zhangxiaofeng05

创建型模式-单例模式

维基百科 单例模式 单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。 实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。 单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。 构建方式 通常单例模式在Java语言中,有两种构建方式: 懒汉方式。指全局的单例实例在第一次被使用时构建。 饿汉方式。指全局的单例实例在类装载时构建。 Java 在Java语言中,单例模式(饿汉模式)应用的例子如下述代码所示: public class Singleton { private static final Singleton INSTANCE = new Singleton(); // Private constructor suppresses // default public constructor private Singleton() {}; public static Singleton getInstance() { return INSTANCE; } } 在Java编程语言中,单例模式(懒汉模式)应用的例子如下述代码所示 (此种方法只能用在JDK5及以后版本(注意 INSTANCE 被声明为 volatile),之前的版本使用“双重检查锁”会发生非预期行为): public class Singleton { private static volatile Singleton INSTANCE = null; // Private constructor suppresses // default public constructor private Singleton() {}; //Thread safe and performance promote public static Singleton getInstance() { if(INSTANCE == null){ synchronized(Singleton.class){ // When more than two threads run into the first null check same time, // to avoid instanced more than one time, it needs to be checked again. if(INSTANCE == null){ INSTANCE = new Singleton(); } } } return INSTANCE; } } 例子 Singleton ...

August 23, 2019 · 1 min · zhangxiaofeng05

创建型模式-建造者模式

维基百科 生成器模式 生成器模式(英:Builder Pattern)是一种设计模式,又名:建造模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 适用性 在以下情况使用生成器模式: 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时; 当构造过程必须允许被构造的对象有不同的表示时。 参与者 Builder 为创建一个Product对象的各个部件指定抽象接口。 ConcreteBuilder 实现Builder的接口以构造和装配该产品的各个部件。 定义并明确它所创建的表示。 提供一个检索产品的接口 Director 构造一个使用Builder接口的对象。 Product 表示被构造的复杂对象。ConcreateBuilder创建该产品的内部表示并定义它的装配过程。 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。 协作 客户创建Director对象,并用它所想要的Builder对象进行配置。 一旦产品部件被生成,导向器就会通知生成器。 生成器处理导向器的请求,并将部件添加到该产品中。 客户从生成器中检索产品。 范例 /** "Product" */ class Pizza { private String dough = ""; private String sauce = ""; private String topping = ""; public void setDough (String dough) { this.dough = dough; } public void setSauce (String sauce) { this.sauce = sauce; } public void setTopping (String topping) { this.topping = topping; } } ''/** "Abstract Builder" */'' abstract class PizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; } public void createNewPizzaProduct() { pizza = new Pizza(); } public abstract void buildDough(); public abstract void buildSauce(); public abstract void buildTopping(); } /** "ConcreteBuilder" */ class HawaiianPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("cross"); } public void buildSauce() { pizza.setSauce("mild"); } public void buildTopping() { pizza.setTopping("ham+pineapple"); } } /** "ConcreteBuilder" */ class SpicyPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("pan baked"); } public void buildSauce() { pizza.setSauce("hot"); } public void buildTopping() { pizza.setTopping("pepperoni+salami"); } } ''/** "Director" */'' class Waiter { private PizzaBuilder pizzaBuilder; public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; } public Pizza getPizza() { return pizzaBuilder.getPizza(); } public void constructPizza() { pizzaBuilder.createNewPizzaProduct(); pizzaBuilder.buildDough(); pizzaBuilder.buildSauce(); pizzaBuilder.buildTopping(); } } /** A customer ordering a pizza. */ class BuilderExample { public static void main(String[] args) { Waiter waiter = new Waiter(); PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder(); PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder(); waiter.setPizzaBuilder ( hawaiian_pizzabuilder ); waiter.constructPizza(); Pizza pizza = waiter.getPizza(); } } 例子 Product ...

August 23, 2019 · 2 min · zhangxiaofeng05

创建型模式-抽象工厂

维基百科 抽象工厂 抽象工厂模式(英语:Abstract factory pattern)是一种软件开发设计模式。抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。 举个例子来说,比如一个抽象工厂类叫做DocumentCreator(文档创建器),此类提供创建若干种产品的接口,包括createLetter()(创建信件)和createResume()(创建简历)。其中,createLetter()返回一个Letter(信件),createResume()返回一个Resume(简历)。系统中还有一些DocumentCreator的具体实现类,包括FancyDocumentCreator和ModernDocumentCreator。这两个类对DocumentCreator的两个方法分别有不同的实现,用来创建不同的“信件”和“简历”(用FancyDocumentCreator的实例可以创建FancyLetter和FancyResume,用ModernDocumentCreator的实例可以创建ModernLetter和ModernResume)。这些具体的“信件”和“简历”类均继承自抽象类,即Letter和Resume类。客户端需要创建“信件”或“简历”时,先要得到一个合适的DocumentCreator实例,然后调用它的方法。一个工厂中创建的每个对象都是同一个主题的(“fancy”或者“modern”)。客户端程序只需要知道得到的对象是“信件”或者“简历”,而不需要知道具体的主题,因此客户端程序从抽象工厂DocumentCreator中得到了Letter或Resume类的引用,而不是具体类的对象引用。 “工厂”是创建产品(对象)的地方,其目的是将产品的创建与产品的使用分离。抽象工厂模式的目的,是将若干抽象产品的接口与不同主题产品的具体实现分离开。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的客户端代码。 使用抽象工厂模式,能够在具体工厂变化的时候,不用修改使用工厂的客户端代码,甚至是在运行时。然而,使用这种模式或者相似的设计模式,可能给编写代码带来不必要的复杂性和额外的工作。正确使用设计模式能够抵消这样的“额外工作” 定义 抽象工厂模式的实质是“提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类。 使用 具体的工厂决定了创建对象的具体类型,而且工厂就是对象实际创建的地方(比如在C++中,用“new”操作符创建对象)。然而,抽象工厂只返回一个指向创建的对象的抽象引用(或指针)。 这样,客户端程序调用抽象工厂引用的方法,由具体工厂完成对象创建,然后客户端程序得到的是抽象产品的引用。如此使客户端代码与对象的创建分离开来。 因为工厂仅仅返回一个抽象产品的引用(或指针),所以客户端程序不知道(也不会牵绊于)工厂创建对象的具体类型。然而,工厂知道具体对象的类型;例如,工厂可能从配置文件中读取某种类型。这时,客户端没有必要指定具体类型,因为已经在配置文件中指定了。通常,这意味着: 客户端代码不知道任何具体类型,也就没必要引入任何相关的头文件或类定义。客户端代码仅仅处理抽象类型。工厂确实创建了具体类型的对象,但是客户端代码仅使用这些对象的抽象接口来访问它们。 如果要增加一个具体类型,只需要修改客户端代码使用另一个工厂即可,而且这个修改通常只是一个文件中的一行代码。不同的工厂创建不同的具体类型的对象,但是和以前一样返回一个抽象类型的引用(或指针),因此客户端代码的其他部分不需要任何改动。这样比修改客户端代码创建新类型的对象简单多了。如果是后者的话,需要修改代码中每一个创建这种对象的地方(而且需要注意的是,这些地方都知道对象的具体类型,而且需要引入具体类型的头文件或类定义)。如果所有的工厂对象都存储在全局的单例对象中,所有的客户端代码到这个单例中访问需要的工厂,那么,更换工厂就非常简单了,仅仅需要更改这个单例对象即可。 代码举例 假设我们有两种产品接口 Button 和 Border ,每一种产品都支持多种系列,比如 Mac 系列和 Windows 系列。这样每个系列的产品分别是 MacButton, WinButton, MacBorder, WinBorder 。为了可以在运行时刻创建一个系列的产品族,我们可以为每个系列的产品族创建一个工厂 MacFactory 和 WinFactory 。每个工厂都有两个方法 CreateButton 和 CreateBorder 并返回对应的产品,可以将这两个方法抽象成一个接口 AbstractFactory 。这样在运行时刻我们可以选择创建需要的产品系列。 public interface Button {} public interface Border {} //实现抽象类 public class MacButton implements Button {} public class MacBorder implements Border {} public class WinButton implements Button {} public class WinBorder implements Border {} //接着实现工厂 public class MacFactory { public static Button createButton() { return new MacButton(); } public static Border createBorder() { return new MacBorder(); } } public class WinFactory { public static Button createButton() { return new WinButton(); } public static Border createBorder() { return new WinBorder(); } } 适用性 在以下情况可以考虑使用抽象工厂模式: ...

August 19, 2019 · 2 min · zhangxiaofeng05

创建型模式-工厂方法

维基百科 工厂方法 工厂方法模式(英语:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。” 创建一个对象常常需要复杂的过程,所以不适合包含在一个复合对象中。创建对象可能会导致大量的重复代码,可能会需要复合对象访问不到的信息,也可能提供不了足够级别的抽象,还可能并不是复合对象概念的一部分。工厂方法模式通过定义一个单独的创建对象的方法来解决这些问题。由子类实现这个方法来创建具体类型的对象。 对象创建中的有些过程包括决定创建哪个对象、管理对象的生命周期,以及管理特定对象的创建和销毁的概念。 工厂 在面向对象程序设计中,工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。 工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象。这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象。 有时,特定类型对象的控制过程比简单地创建一个对象更复杂。在这种情况下,工厂对象就派上用场了。工厂对象可能会动态地创建产品类的对象,或者从对象池中返回一个对象,或者对所创建的对象进行复杂的配置,或者应用其他的操作。 这些类型的对象很有用。几个不同的设计模式都应用了工厂的概念,并可以使用在很多语言中。例如,在《设计模式》一书中,像工厂方法模式、抽象工厂模式、生成器模式,甚至是单例模式都应用了工厂的概念。 代码举例 例如,有一个Button类表示按钮,另有它的两个子类WinButton和MacButton分别代表Windows和Mac风格的按钮,那么这几个类和用于创建它们的工厂类在Java中可以如下实现 //Button class Button{/* ...*/} class WinButton extends Button{/* ...*/} class MacButton extends Button{/* ...*/} //他们的工厂类 interface ButtonFactory{ abstract Button createButton(); } class WinButtonFactory implements ButtonFactory{ Button createButton(){ return new WinButton(); } } class MacButtonFactory implements ButtonFactory{ Button createButton(){ return new MacButton(); } } 简单工厂 普通的工厂方法模式通常伴随着对象的具体类型与工厂具体类型的一一对应,客户端代码根据需要选择合适的具体类型工厂使用。然而,这种选择可能包含复杂的逻辑。这时,可以创建一个单一的工厂类,用以包含这种选择逻辑,根据参数的不同选择实现不同的具体对象。这个工厂类不需要由每个具体产品实现一个自己的具体的工厂类,所以可以将工厂方法设置为静态方法。 而且,工厂方法封装了对象的创建过程。如果创建过程非常复杂(比如依赖于配置文件或用户输入),工厂方法就非常有用了。 比如,一个程序要读取图像文件。程序支持多种图像格式,每种格式都有一个对应的ImageReader类用来读取图像。程序每次读取图像时,需要基于文件信息创建合适类型的ImageReader。这个选择逻辑可以包装在一个简单工厂中: public class ImageReaderFactory { public static ImageReader imageReaderFactoryMethod(InputStream is) { ImageReader product = null; int imageType = determineImageType(is); switch (imageType) { case ImageReaderFactory.GIF: product = new GifReader(is); case ImageReaderFactory.JPEG: product = new JpegReader(is); //... } return product; } } 适用性 下列情况可以考虑使用工厂方法模式: ...

August 19, 2019 · 2 min · zhangxiaofeng05

java接口回调

回调一般用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调。例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。 例如老板A对员工B说,我现在交给你一个任务,并且我把我的电话号码给你,你一旦完成任务就给我打电话。 1.创建一个回调接口 /** * 一个回调接口 */ public interface CallBack { public void doEvent(); } 2.创建回调接口的实现类,此例中,员工干完活后还要干什么事情是老板说了算的。 /** * 回调接口的实现类 */ public class Boss implements CallBack{ @Override public void doEvent() { System.out.println("打电话给老板,告知已完成工作了"); } } 3.创建控制类,也就是本例中的员工对象,他要持有老板的地址(即回调接口) /** * 控制类,也就是本例中的员工对象,他要持有老板的地址(即回调接口) */ public class Employee { CallBack callBack; public Employee(CallBack callBack){ this.callBack=callBack; } public void doWork(){ System.out.println("玩命干活中"); callBack.doEvent(); } } 4.测试类 /** * 测试类 */ public class TestMain { public static void main(String[] args) { Employee employee = new Employee(new Boss()); employee.doWork(); } } 运行结果: ...

August 17, 2019 · 1 min · zhangxiaofeng05

mysql高级排序

表和数据 CREATE TABLE `sqltest` ( `id` int(11) NOT NULL, `name` varchar(45) NOT NULL, `age` int(11) NOT NULL, `score` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id_UNIQUE` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `sqltest` VALUES (1,'土豆',18,100),(2,'地瓜',18,100),(3,'李斯',20,60),(4,'韩非',20,60),(5,'荀子',50,90),(6,'君莫笑',22,80),(7,'寒烟柔',21,80),(8,'包子',26,30),(9,'剑圣',30,0); 排名(row_number) 按分数排序,拿到名次(成绩相同排名不并列) SQL: use sqltest; select st.*,(@rownum:=@rownum+1) as rownum from sqltest st,(select @rownum:=0) potato order by score; 结果: 解释:设置一个伪列@rownum,从1开始计数,依次加1;(select @rownum:=0) potato ,一定要起别名 注意:这是从小到大排;如果需要从大到小的话,order by score desc。 排名(Rank) 按分数排序,拿到名次(成绩相同排名并列,有跳数,比如2个100,1个99,排名就是1,1,3) SQL: use sqltest; select st.*,@rownum:=@rownum+1 as rownum, @curnum:=(case when @prescore=st.score then @curnum else @rownum end) as ScoreRank, @prescore:=st.score as prescore from sqltest st,(select @rownum:=0,@curnum:=0,@prescore:=null) potato order by st.score desc; 结果: ...

August 17, 2019 · 1 min · zhangxiaofeng05

TCP、UDP简单聊天

TCP 客户端套接字:Socket 服务端套接字:ServerSocket TCP(传输控制协议)一种基于连接的通信协议。可靠传输 Server package com.tcp; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * 服务器端 */ public class Server { public static void main(String[] args) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(12345); System.out.println("服务启动:"+serverSocket.getInetAddress().getHostAddress()+":"+serverSocket.getLocalPort()); Socket accept = serverSocket.accept(); System.out.println("客户端:"+accept.getInetAddress().getHostAddress()+":"+accept.getLocalPort()); BufferedReader sis = new BufferedReader(new InputStreamReader(System.in)); BufferedReader is = new BufferedReader(new InputStreamReader(accept.getInputStream())); PrintWriter os = new PrintWriter(new OutputStreamWriter(accept.getOutputStream())); while (true){ String line; if ((line=is.readLine())!=null){ System.out.println("收到客户端:"+line); if (line.equals("bye")){ break; }else { os.println(sis.readLine()); os.flush(); } } } is.close(); os.close(); accept.close(); } catch (IOException e) { e.printStackTrace(); }finally { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } Client package com.tcp; import java.io.*; import java.net.Socket; /** * 客户端 */ public class Client { public static void main(String[] args) { try { Socket socket = new Socket("127.0.0.1",12345); BufferedReader sis = new BufferedReader(new InputStreamReader(System.in)); BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter os = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); String line; while (true){ if ((line=sis.readLine())!=null){ if ("bye".equals(line)){ System.exit(0); } os.println(line); os.flush(); } String readLine = is.readLine(); System.out.println("收到服务端:"+readLine); } } catch (IOException e) { e.printStackTrace(); } } } UDP UDP采用Datagram(数据报)传输,数据包是一种尽力而为的传送数据的方式,它只是 把数据的目的地记录在数据包中,然后就直接放在网络上,系统不保证数据是否能安全到达,或者什么时候可以送到,它并不保证传送质量。 ...

July 30, 2019 · 2 min · zhangxiaofeng05

反射

java.lang.Class 创建一个类,通过编译(javac.exe),生成对应的.class文件。之后使用java.exe加载(JVM的类加载器完成), 此.class文件加载到内存以后,就是一个运行时类,存在缓冲区。那么这个运行时类本身就是一个Class的实例! 一个运行时类只加载一次。 举例 import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class RelfectTest{ public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException { Class<Person> personClass = Person.class; //通过反射创建对象 Person person = personClass.newInstance(); System.out.println(person); //通过反射赋值-------public属性 Field name = personClass.getField("name"); name.set(person,"土豆"); System.out.println(person); //通过反射赋值------private或者默认(不写)属性 Field age = personClass.getDeclaredField("age"); age.setAccessible(true); age.set(person,18); System.out.println(person); //通过反射调用指定方法--没有参数 Method show = personClass.getMethod("show"); show.invoke(person); //通过反射调用指定方法--有参数 Method say = personClass.getMethod("say", String.class); say.invoke(person,"welcome"); } } class Person{ public String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name+"----"+age; } public void show(){ System.out.println("Person类的show..."); } public void say(String word){ System.out.println(name+" "+word); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 拓展 Person类 ...

July 28, 2019 · 5 min · zhangxiaofeng05