当前位置: 首页 > news >正文

手机网站开发利用流程站长友情链接平台

手机网站开发利用流程,站长友情链接平台,拱墅抖音seo搜索排名推广,适合大学生做的网站有哪些目录 常量特定方法 职责链模式的枚举实现 状态机模式的枚举实现 多路分发 1、使用枚举类型实现分发 2、使用常量特定方法实现分发 3、使用EnumMap实现分发 4、使用二维数组实现分发 本笔记参考自: 《On Java 中文版》 常量特定方法 在Java中,我们…

目录

常量特定方法

职责链模式的枚举实现

状态机模式的枚举实现

多路分发

1、使用枚举类型实现分发

2、使用常量特定方法实现分发

3、使用EnumMap实现分发

4、使用二维数组实现分发


本笔记参考自: 《On Java 中文版》


常量特定方法

        在Java中,我们可以通过为每个枚举实例编写不同的方法,来赋予它们不同的行为。一个方式是在枚举类型中定义抽象方法,并在枚举实例中实现它:

【例子:为枚举实例编写方法】

import java.text.DateFormat;
import java.util.Date;public enum ConstantSpecificMethod {DATE_TIME {@OverrideString getInfo() {return DateFormat.getDateInstance().format(new Date());}},CLASSPATH {@OverrideString getInfo() {// getenv()方法用于获取指定环境变量的值return System.getenv("CLASSPATH");}},VERSION {@OverrideString getInfo() { // 获取由输入指定的属性return System.getProperty("java.version");}};abstract String getInfo();public static void main(String[] args) {for (ConstantSpecificMethod csm : values())System.out.println(csm.getInfo());}
}

        程序执行的结果是:

        在这个例子中,我们通过关联的枚举实例来调用对应的方法,这通常被称为表驱动模式

        这里需要复习一点:在面向对象的编程中,不同的行为是和不同的类相关联的。而上述枚举的每个实例都拥有各自不同的行为,这就表明每个实例都相当于不同的类型(体现了多态)。它们的共同点在于它们的基类ConstantSpecificMethod

        但这并不意味着枚举实例能够等价于普通的类:

【例子:枚举实例和类之间的不同点】

enum LikeClasses {A {@Overridevoid behavior() {System.out.println("A");}},B {@Overridevoid behavior() {System.out.println("B");}},C {@Overridevoid behavior() {System.out.println("C");}};abstract void behavior();
}public class NotClasses {
//    void f1(LikeClasses.A instance) {
//    } // 不可行的操作
}

        编译器并不允许f1()的操作:将枚举实例作为类的类型进行使用。为了解释这一点,可以对程序进行反编译javap -c LikeClasses

反编译告诉我们,每个枚举元素都是LikeClasses的一个static final实例。实例无法作为类型进行使用。

        除此之外,不同于内部类,因为枚举实例是静态的,所以我们无法通过外部类LikeClasses直接访问其内部的枚举实例(具体而言,我们无法在非静态域中访问外部类的静态成员)。

(与匿名内部类相比,常量特定方法要显得更加简洁。)

        除此之外,常量特定方法也支持重写

【例子:重写常量特定方法】

public enum OverrideConstantSpecific {NUT, BOLT,WASHER {@Overridepublic void f() {System.out.println("重写后的f()方法");}};void f() {System.out.println("默认的f()方法");}public static void main(String[] args) {for (OverrideConstantSpecific ocs : values()) {System.out.print(ocs + ": ");ocs.f();}}
}

        程序执行的结果是:

    这些特性使得我们在通常情况下,可以将枚举作为类来使用。

职责链模式的枚举实现

||| 职责链模式:先创建一批用于解决目标问题的不同方法,并将它们链式排列。当一个请求到达时,它会顺着这条“链”向下走,直到遇到可以解决当前请求的方法。

        下面的例子描述了一个邮局模型:使用常规方法处理信件,当前方法不可行时,尝试其他方法,直到无法处理该信件为止(称为“死信”)。

    可以将每种处理方法视作一种策略,策略的列表组成了一条职责链。

【例子:邮局模型】

import onjava.Enums;import java.util.Iterator;class Mail {enum GeneralDelivery {YES, NO1, NO2, NO3, NO4, NO5} // 是否使用常规方式处理enum Scannability {UNSCANNABLE, YES1, YES2, YES3, YES4} // 是否可以扫描enum Readability {ILLEGIBLE, YES1, YES2, YES3, YES4} // 是否可读enum Address {INCORRECT, OK1, OK2, OK3, OK4, OK5, OK6}enum ReturnAddress {MISSING, OK1, OK2, OK3, OK4, OK5}// 创建枚举变量GeneralDelivery generalDelivery;Scannability scannability;Readability readability;Address address;ReturnAddress returnAddress;static long counter = 0;long id = counter++;@Overridepublic String toString() {return "邮件" + id;}public String details() {return toString() +",一般交付:" + generalDelivery + ",地址是否可以扫描:" + scannability +"\n地址是否可读:" + readability + ",目标地址:" + address +"\n返还地址:" + returnAddress;}// 用于生成测试邮件:// (Enums类可见笔记 进阶1-1)public static Mail randomMail() {Mail m = new Mail();// 为枚举实例随机赋值:m.generalDelivery =Enums.random(GeneralDelivery.class);m.scannability =Enums.random(Scannability.class);m.readability =Enums.random(Readability.class);m.address =Enums.random(Address.class);m.returnAddress =Enums.random(ReturnAddress.class);return m;}// count无需修改,可以使用finalpublic static Iterable<Mail> generator(final int count) {return new Iterable<Mail>() {int n = count;@Overridepublic Iterator<Mail> iterator() {return new Iterator<Mail>() {@Overridepublic boolean hasNext() {return n-- > 0;}@Overridepublic Mail next() {return randomMail();}};}};}
}public class PostOffice {// 使用职责链模式:enum MailHandler {GENERAL_DELIVERY {@Overrideboolean handle(Mail m) {switch (m.generalDelivery) {case YES:System.out.println("对" + m + "使用常规方法进行处理");return true;default:return false;}}},MACHINE_SCAN {@Overrideboolean handle(Mail m) {switch (m.scannability) {case UNSCANNABLE:return false;default:switch (m.address) {case INCORRECT:return false;default:System.out.println("自动派送" + m);return true;}}}},VISUAL_INSPECTION {@Overrideboolean handle(Mail m) {switch (m.readability) {case ILLEGIBLE:return false;default:switch (m.address) {case INCORRECT:return false;default:System.out.println("常规派送" + m);return true;}}}},RETURN_TO_SENDER {@Overrideboolean handle(Mail m) {switch (m.returnAddress) {case MISSING:return false;default:System.out.println("将" + m + "返还给发送者");return true;}}};abstract boolean handle(Mail m);}static void handle(Mail m) {for (MailHandler handler : MailHandler.values())if (handler.handle(m))return;System.out.println(m + "是一封死信");}public static void main(String[] args) {for (Mail mail : Mail.generator(5)) {System.out.println(mail.details());handle(mail);System.out.println("============");}}
}

        程序执行的结果是:

        职责链模式MailHandler枚举中得到应用,并且枚举的定义顺序决定了各个策略在邮件上的应用顺序。


状态机模式的枚举实现

||| 状态机的解释:

  1. 具有有限数量的特定状态。
  2. 每个状态都有输入。根据输入,可以实现状态之间的跳转,但也存在瞬态
  3. 当任务执行完毕后,立即跳出所有状态。

        用枚举表示状态机模式的一个优势是,枚举可以限制出现的状态集的大小:

【例子:自动售货机】

        首先创建一个用于输入的枚举:

import java.util.Random;public enum Input {CENT(1), COIN(10), TEN_COIN(100),TOOTHBRUSH(150.0f), TOWEL(200.0f), SOAP(80.0f),ABORT_TRANSACTION {@Overridepublic float amount() {throw new RuntimeException("ABORT.amount()");}},STOP { // STOP必须是最后一个实例@Overridepublic float amount() {throw new RuntimeException("SHUT_DOWN.amount()");}};float value;Input(float value) {this.value = value;}Input() {}float amount() { // 单位为:毛return value;}static Random rand = new Random(47);public static Input randomSelection() {// 不包括STOP:return values()[rand.nextInt(values().length - 1)];}
}

        amount()会返回物品对应的价格。由于枚举的限制,amount()会作用于所有的枚举实例。很显然,对最后两个实例调用它并不合适,因此这里需要重写amount()

        接下来实现自动售货机的状态机:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.function.Supplier;
import java.util.stream.Collectors;enum Category {MONEY(Input.CENT, Input.COIN, Input.TEN_COIN),ITEM_SELECTION(Input.TOOTHBRUSH, Input.TOWEL, Input.SOAP),QUIT_TRANSACTION(Input.ABORT_TRANSACTION),SHUT_DOWN(Input.STOP);private Input[] values;Category(Input... types) {values = types;}private static EnumMap<Input, Category> categories =new EnumMap<>(Input.class);static {for (Category c : Category.class.getEnumConstants())for (Input type : c.values)categories.put(type, c);}public static Category categorize(Input input) {return categories.get(input);}
}public class VendingMachine {private static State state = State.RESTING;private static float amount = 0;private static Input selection = null;enum StateDuration { // 用于标记enum中的瞬态TRANSIENT;}enum State {RESTING { // 休眠中@Overridevoid next(Input input) {switch (Category.categorize(input)) {case MONEY:amount += input.amount();state = ADDING_MONEY; // 重新赋值statebreak;case SHUT_DOWN:state = TERMINAL;default:}}},ADDING_MONEY { // 添加金钱,购买商品@Overridevoid next(Input input) {switch (Category.categorize(input)) {case MONEY:amount += input.amount();break;case ITEM_SELECTION:selection = input;if (amount < selection.amount())System.out.println("当前余额不足以购买" + selection);elsestate = DISPENSING; // 下个状态也可以是瞬态break;case QUIT_TRANSACTION:state = GIVING_CHANGE;break;case SHUT_DOWN:state = TERMINAL;default:}}},DISPENSING(StateDuration.TRANSIENT) { // 取出商品(注意:实例的初始化方式并不相同)@Overridevoid next() {System.out.println("这是你购买的物品:" + selection);amount -= selection.amount();state = GIVING_CHANGE;}},GIVING_CHANGE(StateDuration.TRANSIENT) { // 找钱@Overridevoid next() {if (amount > 0) {System.out.println("这是找零:" + amount);amount = 0;}state = RESTING;}},TERMINAL { // 关闭机器@Overridevoid output() {System.out.println("停止运行");}};// 判断当前状态是否为瞬态private boolean isTransient = false;State() {}State(StateDuration trans) {isTransient = true; // 说明当前处于瞬态}void next(Input input) {throw new RuntimeException("仅应该对非瞬态调用next(Input input)");}void next() {throw new RuntimeException("仅应该对StateDuration.TRANSIENT(瞬态)调用next()");}void output() {System.out.println(amount);}}static void run(Supplier<Input> gen) {while (state != State.TERMINAL) {state.next(gen.get());while (state.isTransient)state.next();state.output();}}public static void main(String[] args) {Supplier<Input> gen = new RandomInputSupplier();if (args.length == 1)gen = new FileInputSupplier(args[0]);run(gen);}
}class RandomInputSupplier implements Supplier<Input> {@Overridepublic Input get() {return Input.randomSelection();}
}// 从文件输入:
class FileInputSupplier implements Supplier<Input> {private Iterator<String> input;FileInputSupplier(String fileName) {try {input = Files.lines(Paths.get(fileName)) // 行级的Stream流.flatMap(s -> Arrays.stream(s.split(";"))) // 输入文件的信息是由分号分隔的.map(String::trim).collect(Collectors.toList()).iterator();} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic Input get() {if (!input.hasNext())return null;return Enum.valueOf(Input.class, input.next().trim());}
}

        若不从文件导入数据,则售货机在开机后就会一直运行下去。为了完整演示整个状态机的流程,这里使用文件输入。测试文件如下:

CENT; TEN_COIN; TOOTHBRUSH;
COIN; TEN_COIN; TEN_COIN; SOAP;
TEN_COIN;  TEN_COIN; CENT; COIN; TOWEL;
ABORT_TRANSACTION;
STOP;

        对应该文件,程序执行的结果是:

        在这种模式中,枚举在switch上发挥了它的功能。

        在VendingMachine类中存在着两个瞬态:DISPENSINGGIVING_CHANGE。状态机会在各种状态之间移动,知道不再处于某个瞬态中为止(对这个例子而言,“取出商品”和“找零”的动作是瞬态,售货机不应该停留在这些状态中)。

    然而,这种设计存在一个限制:State的枚举实例是静态的,这意味着这些实例只能访问其外部类(即VendingMachine)中的静态字段。这意味着只能存在一个VendingMachine实例。

多路分发

        若一个程序中存在多个交互类型,这个程序有可能变得很混乱。举一个例子:

public abstract class Number {abstract Number plus(Number number);abstract Number multiply(Number number);//...
}

此处的Number类是某个系统中所有数值类型的基类,其中包括一些进行数值运算所需要的方法。

        现在假设ab分别属于Number的某个子类,并且都使用Number引用指示它们。若要处理语句a.plus(b),一个简单的想法是我们需要同时知道ab的具体类型。遗憾的是,Java只能进行单路分发,这意味着我们只能对一个类型未知的对象进行操作

        多路分发并不是同时对多个类型未知的对象进行操作,而是进行了多次的方法调用

    使用多路分发,就必须对每个类型都执行虚拟调用。并且,若操作发生在不同的交互类型层次结构中,则还需要对每个层次结构都执行虚拟操作。

        接下来通过一个“猜拳”的例子展示多路分发的使用:

【例子:“猜拳”游戏】

        首先确定“猜拳”的三种结果:

public enum Outcome {WIN, // 赢LOSE, // 输DRAW // 平局
}

        接下来实现多路分发的接口:

public interface Item {Outcome compete(Item it);Outcome eval(Paper p);Outcome eval(Scissors p);Outcome eval(Rock p);
}

        接下来为“石头”、“剪刀”和“布”分别匹配它们的胜负情况:

        然后,通过调用compete()方法,就可以简单地判断“猜拳”的胜负:

import java.util.Random;public class RoShamBo1 {static final int SIZE = 10;private static Random rand = new Random(47);public static Item newItem() {switch (rand.nextInt(3)) {default: // 必须有的defaultcase 0:return new Scissors();case 1:return new Paper();case 2:return new Rock();}}public static void match(Item a, Item b) {System.out.println(a + " vs. " + b + " " + a.compete(b));}public static void main(String[] args) {for (int i = 0; i < SIZE; i++)match(newItem(), newItem());}
}

        程序执行的结果是:

        在match()方法中,程序可以知道a的类型,进而调用对应的compete()方法。在compete()中调用eval()方法时,会向其中传入一个this引用,这个this引用用于保留原本a的类型。

    如上所示,多路分发的构筑较为麻烦。但好处显而易见:我们在调用中保持住了语法的优雅。

        因为枚举实例不是类型,因此我们无法通过重载eval()方法的方式实现目标。但还是有别的方法可以进行实现。 

1、使用枚举类型实现分发

        一种方法是在初始化枚举实例时进行操作。通过这种方式,我们最终可以得到一个类似于查询表的结构:

【例子:初始化枚举实现“猜拳”】

import static enums.Outcome.*;// 规定Competitor接口,通过接口来操作枚举:
public enum RoShamBo2 implements Competitor<RoShamBo2> {PAPER(DRAW, LOSE, WIN),SCISSORS(WIN, DRAW, LOSE),ROCK(LOSE, WIN, DRAW);private Outcome vPAPER, vSCISSORS, vROCK;// 针对“石头”、“剪刀”和“布”这三种情况,初始化后三个私有变量的值也会发生改变RoShamBo2(Outcome paper,Outcome scissors, Outcome rock) {this.vPAPER = paper;this.vSCISSORS = scissors;this.vROCK = rock;}@Overridepublic Outcome compete(RoShamBo2 competitor) {switch (competitor) {default:case ROCK: // 若对方出的是石头return vROCK; // 那么就返回当前对象遇到石头时会得出的结果case PAPER: // 布return vPAPER;case SCISSORS: // 剪刀return vSCISSORS;}}public static void main(String[] args) {RoShamBo.play(RoShamBo2.class, 10); // 独立出来的方法,用于操作猜拳}
}

        程序执行的结果是:

        书本在此处将原本用于操作枚举的代码分隔开来,以此增加了代码的复用率。以下是复用的代码(Competitor接口及RoShamBo类)的实现:

【例子:用于操作枚举的工具】

        为了统一现有的枚举及之后会出现的枚举的操作,可以使用Competitor接口:

public interface Competitor<T extends Competitor<T>> {Outcome compete(T competitor);
}

        我们规定,所有的“石头剪刀布”枚举都来自于这种竞争者(Competitor)关系,自限定类型(笔记18-4)可以很好地满足这一点。

    与一般的泛型相比,自限定类型对继承关系有更加严格的要求。对于上述的compete()方法而言,它只会接受Competitor及其子类。

         然后是生成随机结果的RoShamBo类:

import onjava.Enums;public class RoShamBo extends EnumClass {// 使用了自限定类型:public static <T extends Competitor<T>>void match(T a, T b) {System.out.println(a + " vs. " + b + " " + a.compete(b));}// 这种方式同时继承了一个基类和一个接口:public static <T extends Enum<T> & Competitor<T>>void play(Class<T> rsbClass, int size) {for (int i = 0; i < size; i++)match(Enums.random(rsbClass), Enums.random(rsbClass));}
}

        这个类包含了一个用于接收的paly()方法和真正调用枚举操作的match()方法。play()方法规定,传入的数据必须是一个实现了Competitor接口的枚举。

        需要注意一点:由于play()方法不需要返回值,换言之,在离开泛型的边界上并没有需要使用到类型参数T的地方,因此参数T在这里似乎是不必要的。但如果将Class<T>替换为Class<?>这种通配符形式,就会发生报错:

这是因为通配符【?】无法继承多个基类,因此这里只能使用类型参数T


2、使用常量特定方法实现分发

        遗憾的是,枚举本身并不能作为对象类型使用。因此我们没有办法通过传递实例来进行多路分发。在这里,一个好的办法是使用switch语句:

【例子:使用switch分发】

import static enums.Outcome.*;public enum RoShamBo3 implements Competitor<RoShamBo3> {PAPER {@Overridepublic Outcome compete(RoShamBo3 competitor) {switch (competitor) {default:case PAPER:return DRAW;case SCISSORS:return LOSE;case ROCK:return WIN;}}},SCISSORS {@Overridepublic Outcome compete(RoShamBo3 competitor) {switch (competitor) {default:case PAPER:return WIN;case SCISSORS:return DRAW;case ROCK:return LOSE;}}},ROCK {@Overridepublic Outcome compete(RoShamBo3 competitor) {switch (competitor) {default:case PAPER:return LOSE;case SCISSORS:return WIN;case ROCK:return DRAW;}}};// 此处的方法声明只是为了便于理解:@Overridepublic abstract Outcome compete(RoShamBo3 competitor);public static void main(String[] args) {RoShamBo.play(RoShamBo3.class, 10);}
}

        程序执行的结果与上一个例子相同:

        这种写法无疑是繁琐的。因此,我们可以尝试对其进行优化。用三目运算符来取代switch语句,压缩代码空间:

【例子:使用三目运算符进行优化】

public enum RoShamBo4 implements Competitor<RoShamBo4> {ROCK {@Overridepublic Outcome compete(RoShamBo4 competitor) {return compete(SCISSORS, competitor);}},SCISSORS {@Overridepublic Outcome compete(RoShamBo4 competitor) {return compete(PAPER, competitor);}},PAPER {@Overridepublic Outcome compete(RoShamBo4 competitor) {return compete(ROCK, competitor);}};// 重载的compete()方法// 第一个参数表示的是胜利条件Outcome compete(RoShamBo4 loser, RoShamBo4 competitor) {return ((competitor == this) ? Outcome.DRAW : // 通过this确定平局条件(competitor == loser) ? Outcome.WIN : // 通过传入参数确定胜利条件Outcome.LOSE);  // 那么剩下的就是失败条件了}public static void main(String[] args) {RoShamBo.play(RoShamBo4.class, 10);}
}

        由于输出结果是一致的,因此此处不再展示。

    当然,更加简短的代码有可能带来更大的理解成本。在大型的系统开发过程中应该要注意这一点。


3、使用EnumMap实现分发

        EnumMap是专门为enum设计的高效Map。使用它,我们可以更好地实现多路分发。具体而言,当我们需要进行两路分发时,我们可以使用嵌套的EnumMap

【例子:使用EnumMap实现分发】

import java.util.EnumMap;import static enums.Outcome.*;public enum RoShamBo5 implements Competitor<RoShamBo5> {PAPER, SCISSORS, ROCK;// 使用Class进行初始化,规定Map的键值必须是RoShamBo5类型static EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>>table = new EnumMap<>(RoShamBo5.class);static {// 使用for循环,为table每个键创建其对应的对象for (RoShamBo5 it : RoShamBo5.values())table.put(it, new EnumMap<>(RoShamBo5.class));// 为对象填充具体的信息initRow(PAPER, DRAW, LOSE, WIN);initRow(SCISSORS, WIN, DRAW, LOSE);initRow(ROCK, LOSE, WIN, DRAW);}static void initRow(RoShamBo5 it,Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {EnumMap<RoShamBo5, Outcome> row =RoShamBo5.table.get(it); // get()方法会返回指定键对应的值(一个EnumMap的对象)row.put(RoShamBo5.PAPER, vPAPER);row.put(RoShamBo5.SCISSORS, vSCISSORS);row.put(RoShamBo5.ROCK, vROCK);}@Overridepublic Outcome compete(RoShamBo5 competitor) {return table.get(this).get(competitor); // 两次get(),两次分发}public static void main(String[] args) {RoShamBo.play(RoShamBo5.class, 10);}
}

        这里需要注意的是static子句。我们需要在RoShamBo5的其余部分初始化完毕之前,将所有的胜负信息填充到table里面。因此需要使用静态的初始化方式。


4、使用二维数组实现分发

        在“石头剪刀布”中,每一个枚举实例都会对应一个固定的值(可以用ordinal()获取)。这使得使用二维数组实现两路分发成为可能:

【例子:使用二维数组实现分发】

import static enums.Outcome.*;public enum RoShamBo6 implements Competitor<RoShamBo6> {PAPER, SCISSORS, ROCK;// 胜负顺序需要根据枚举的定义顺序进行调整:private static Outcome[][] table = {{DRAW, LOSE, WIN}, // 布{WIN, DRAW, LOSE}, // 剪刀{LOSE, WIN, DRAW}, // 石头};@Overridepublic Outcome compete(RoShamBo6 competitor) {return table[this.ordinal()][this.ordinal()];}public static void main(String[] args) {RoShamBo.play(RoShamBo6.class, 10);}
}

        这种写法有着极高的效率,以及简短易懂的代码。但与之相对,它的缺点也正是在于其使用了数组:一方面,在面对更加大量的数据时,使用数组或许会漏掉某些麻烦的情况;除此之外,这种写法更为死板——从数组中得到的依旧只是一个常量的结果。

    针对第二个缺点,我们可以使用函数对象来进行一些变化,使得数组不再那么僵硬。并且,在处理特定问题时,“表驱动模式”可以发挥出强大的力量。


文章转载自:
http://dinncoperry.bkqw.cn
http://dinncohelping.bkqw.cn
http://dinncodaintiness.bkqw.cn
http://dinncoyeanling.bkqw.cn
http://dinncoconcord.bkqw.cn
http://dinnconectary.bkqw.cn
http://dinncolush.bkqw.cn
http://dinncodepartment.bkqw.cn
http://dinncoreposefully.bkqw.cn
http://dinncounsold.bkqw.cn
http://dinncovertex.bkqw.cn
http://dinncozombiism.bkqw.cn
http://dinncohurl.bkqw.cn
http://dinncocopperhead.bkqw.cn
http://dinncosesterce.bkqw.cn
http://dinncomandibular.bkqw.cn
http://dinncogerenuk.bkqw.cn
http://dinncoflintiness.bkqw.cn
http://dinncojugate.bkqw.cn
http://dinncoperissodactyla.bkqw.cn
http://dinncoimplication.bkqw.cn
http://dinncopostboat.bkqw.cn
http://dinncocollywobbles.bkqw.cn
http://dinncomicron.bkqw.cn
http://dinncobeltane.bkqw.cn
http://dinncopalmation.bkqw.cn
http://dinncoprofess.bkqw.cn
http://dinncotheftproof.bkqw.cn
http://dinncoslum.bkqw.cn
http://dinncobheestie.bkqw.cn
http://dinncohoudan.bkqw.cn
http://dinncorelaxant.bkqw.cn
http://dinncodoorhead.bkqw.cn
http://dinncoswati.bkqw.cn
http://dinncooffaly.bkqw.cn
http://dinncoriflebird.bkqw.cn
http://dinncoshakeable.bkqw.cn
http://dinnconumeroscope.bkqw.cn
http://dinncogesamtkunstwerk.bkqw.cn
http://dinncosulfonmethane.bkqw.cn
http://dinncoaduncate.bkqw.cn
http://dinncoseptember.bkqw.cn
http://dinncoausterely.bkqw.cn
http://dinncofete.bkqw.cn
http://dinncoanthranilate.bkqw.cn
http://dinncohemodia.bkqw.cn
http://dinncounlit.bkqw.cn
http://dinncoxenocryst.bkqw.cn
http://dinncocantiga.bkqw.cn
http://dinncoflossy.bkqw.cn
http://dinncorhesis.bkqw.cn
http://dinncomillepede.bkqw.cn
http://dinncobicentennial.bkqw.cn
http://dinncodivining.bkqw.cn
http://dinncouaa.bkqw.cn
http://dinncodiaphragmatic.bkqw.cn
http://dinncolifter.bkqw.cn
http://dinncopachalic.bkqw.cn
http://dinncofaintheart.bkqw.cn
http://dinncohomalographic.bkqw.cn
http://dinncodichotic.bkqw.cn
http://dinncomicrocrystal.bkqw.cn
http://dinncooddment.bkqw.cn
http://dinncosamite.bkqw.cn
http://dinncomercapto.bkqw.cn
http://dinncovesiculous.bkqw.cn
http://dinncoautoantibody.bkqw.cn
http://dinncoaquicolous.bkqw.cn
http://dinncointolerance.bkqw.cn
http://dinncosulfonal.bkqw.cn
http://dinncodecided.bkqw.cn
http://dinncotribespeople.bkqw.cn
http://dinncokleptomaniac.bkqw.cn
http://dinnconimble.bkqw.cn
http://dinncogoosey.bkqw.cn
http://dinncoadman.bkqw.cn
http://dinncoserpentinite.bkqw.cn
http://dinncogirder.bkqw.cn
http://dinncoheterochromatic.bkqw.cn
http://dinncointrada.bkqw.cn
http://dinncochibcha.bkqw.cn
http://dinncoocclusion.bkqw.cn
http://dinncospun.bkqw.cn
http://dinncofritting.bkqw.cn
http://dinncodewclaw.bkqw.cn
http://dinncounisist.bkqw.cn
http://dinncoundisputed.bkqw.cn
http://dinncomilesian.bkqw.cn
http://dinncocachucha.bkqw.cn
http://dinncoheaviest.bkqw.cn
http://dinncoappurtenant.bkqw.cn
http://dinncohousekeeping.bkqw.cn
http://dinncoduroc.bkqw.cn
http://dinncogayly.bkqw.cn
http://dinncotelferage.bkqw.cn
http://dinncopeelite.bkqw.cn
http://dinncodorking.bkqw.cn
http://dinncoxenoantigen.bkqw.cn
http://dinncometachrome.bkqw.cn
http://dinncohidalgo.bkqw.cn
http://www.dinnco.com/news/130841.html

相关文章:

  • 德阳建设网站的公司合肥新闻 今天 最新消息
  • 网站建设灬金手指科杰站长工具星空传媒
  • 做海报那个网站好优化
  • 公安网站备案服务类型怎么在百度推广
  • 东莞网站建设推广咨询平台网站设计模板
  • 做的好的网站开发网络营销活动案例
  • 百汇游戏网站开发商镇江网站定制
  • 合优网合川找工作求职招聘上海seo外包
  • 最新的疫情最新消息手机网站seo免费软件
  • div css 中文网站模板nba排名榜
  • 福建省漳州市芗城区疫情最新情况网站google搜索优化
  • wordpress 函数调用在线seo推广软件
  • 做卖东西的网站seo承诺排名的公司
  • psd模板怎么做网站百度招聘2022年最新招聘
  • 怎么做logo网站做网站平台需要多少钱
  • 个体户公司名称怎么取官网seo关键词排名系统
  • 二维码生成器下载西安网站优化培训
  • 建设企业网站找谁推广运营是什么工作
  • 电子商务网站建设报价网络营销软件大全
  • 网站建设基本流程详细说明国外网站排名前十
  • 福州市交通建设集团网站百度下载安装免费版
  • 企业网站展示生产的处方药介绍处罚案件推广商
  • 洛阳网站建站太原做网站推广的公司
  • 软件做网站 编程自己写百度联盟怎么赚钱
  • 国际交流网站平台有哪些网站推广的策略
  • 网站建设需要哪些技术自己如何做链接推广
  • wordpress is adminseo搜索价格
  • 国内外优秀网站seo优化基础教程pdf
  • 武汉百度做网站抖音seo优化公司
  • 网站建设电脑端手机端百度seo流量