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

【JavaScript】面向对象与设计模式

在这里插入图片描述

个人主页:Guiat
归属专栏:HTML CSS JavaScript

在这里插入图片描述

文章目录

  • 1. JavaScript 中的面向对象编程
    • 1.1 对象基础
    • 1.2 构造函数
    • 1.3 原型和原型链
    • 1.4 ES6 类
    • 1.5 继承
    • 1.6 封装
  • 2. 创建型设计模式
    • 2.1 工厂模式
    • 2.2 单例模式
    • 2.3 建造者模式
    • 2.4 原型模式
  • 3. 结构型设计模式
    • 3.1 适配器模式
    • 3.2 装饰器模式
    • 3.3 代理模式
    • 3.4 组合模式
  • 4. 行为型设计模式
    • 4.1 观察者模式
    • 4.2 策略模式
    • 4.3 命令模式
    • 4.4 迭代器模式
    • 4.5 中介者模式
  • 5. 实际应用案例
    • 5.1 表单验证系统

正文

1. JavaScript 中的面向对象编程

1.1 对象基础

在 JavaScript 中,对象是键值对的集合,几乎所有事物都是对象。

// 对象字面量
const person = {
  name: 'John',
  age: 30,
  greet: function() {
    return `Hello, my name is ${this.name}`;
  }
};

// 访问属性
console.log(person.name); // "John"
console.log(person['age']); // 30

// 调用方法
console.log(person.greet()); // "Hello, my name is John"

1.2 构造函数

构造函数用于创建和初始化对象。

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    return `Hello, my name is ${this.name}`;
  };
}

// 使用 new 关键字创建实例
const john = new Person('John', 30);
const jane = new Person('Jane', 25);

console.log(john.greet()); // "Hello, my name is John"
console.log(jane.greet()); // "Hello, my name is Jane"

// 验证实例类型
console.log(john instanceof Person); // true

1.3 原型和原型链

每个 JavaScript 对象都连接到一个原型对象,可以从中继承属性和方法。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 在原型上添加方法
Person.prototype.greet = function() {
  return `Hello, my name is ${this.name}`;
};

const john = new Person('John', 30);
const jane = new Person('Jane', 25);

console.log(john.greet()); // "Hello, my name is John"
console.log(john.greet === jane.greet); // true - 方法共享

// 原型链
console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null

1.4 ES6 类

ES6 引入了类语法,使面向对象编程更直观。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  // 实例方法
  greet() {
    return `Hello, my name is ${this.name}`;
  }
  
  // 静态方法
  static createAnonymous() {
    return new Person('Anonymous', 0);
  }
  
  // getter
  get profile() {
    return `${this.name}, ${this.age} years old`;
  }
  
  // setter
  set profile(value) {
    [this.name, this.age] = value.split(',');
    this.age = parseInt(this.age, 10);
  }
}

const john = new Person('John', 30);
console.log(john.greet()); // "Hello, my name is John"

// 静态方法调用
const anonymous = Person.createAnonymous();
console.log(anonymous.name); // "Anonymous"

1.5 继承

继承允许一个类基于另一个类创建,共享和扩展其功能。

// ES5 继承
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  return `Hello, my name is ${this.name}`;
};

function Employee(name, age, company) {
  // 调用父类构造函数
  Person.call(this, name, age);
  this.company = company;
}

// 设置原型链
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

// 添加新方法
Employee.prototype.work = function() {
  return `${this.name} works at ${this.company}`;
};

// ES6 继承
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    return `Hello, my name is ${this.name}`;
  }
}

class Employee extends Person {
  constructor(name, age, company) {
    super(name, age); // 调用父类构造函数
    this.company = company;
  }
  
  work() {
    return `${this.name} works at ${this.company}`;
  }
  
  // 覆盖父类方法
  greet() {
    return `${super.greet()} and I work at ${this.company}`;
  }
}

const jane = new Employee('Jane', 25, 'Facebook');
console.log(jane.greet()); // "Hello, my name is Jane and I work at Facebook"

1.6 封装

封装是隐藏对象内部状态和实现细节的技术。

// 使用闭包实现私有变量
function Person(name, age) {
  // 私有变量
  let _name = name;
  let _age = age;
  
  // 公共接口
  this.getName = function() {
    return _name;
  };
  
  this.setName = function(name) {
    if (name.length > 0) {
      _name = name;
    }
  };
}

// ES2022 私有字段和方法
class Person {
  // 私有字段
  #name;
  #age;
  
  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }
  
  // 公共方法
  getName() {
    return this.#name;
  }
  
  // 私有方法
  #validateAge(age) {
    return age > 0 && age < 120;
  }
}

2. 创建型设计模式

创建型设计模式关注对象的创建机制,以适合特定情况的方式创建对象。

2.1 工厂模式

工厂模式通过一个中央函数创建对象。

// 简单工厂
function createUser(type) {
  if (type === 'admin') {
    return {
      name: 'Admin User',
      permissions: ['read', 'write', 'delete']
    };
  } else if (type === 'user') {
    return {
      name: 'Regular User',
      permissions: ['read']
    };
  }
}

const adminUser = createUser('admin');
console.log(adminUser.permissions); // ["read", "write", "delete"]

// 工厂方法
class UserFactory {
  static createAdmin(name) {
    return {
      name,
      permissions: ['read', 'write', 'delete'],
      role: 'admin'
    };
  }
  
  static createRegular(name) {
    return {
      name,
      permissions: ['read'],
      role: 'user'
    };
  }
}

const admin = UserFactory.createAdmin('John');
const user = UserFactory.createRegular('Jane');

2.2 单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。

// 简单单例
const Singleton = (function() {
  let instance;
  
  function createInstance() {
    return {
      name: 'Singleton Instance',
      getData: function() {
        return this.name;
      }
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true

// ES6 单例
class Database {
  constructor(host, port) {
    if (Database.instance) {
      return Database.instance;
    }
    
    this.host = host;
    this.port = port;
    this.connected = false;
    
    Database.instance = this;
  }
  
  connect() {
    if (this.connected) {
      return this;
    }
    console.log(`Connecting to ${this.host}:${this.port}`);
    this.connected = true;
    return this;
  }
}

const db1 = new Database('localhost', 3306).connect();
const db2 = new Database('example.com', 8080).connect();
console.log(db1 === db2); // true
console.log(db2.host); // "localhost" (不是 "example.com")

2.3 建造者模式

建造者模式将复杂对象的构建与其表示分离,使同一构建过程可创建不同表示。

// 建造者模式
class HouseBuilder {
  constructor() {
    this.house = {};
  }
  
  setBuildingType(buildingType) {
    this.house.buildingType = buildingType;
    return this;
  }
  
  setWallMaterial(wallMaterial) {
    this.house.wallMaterial = wallMaterial;
    return this;
  }
  
  setNumberOfDoors(number) {
    this.house.doors = number;
    return this;
  }
  
  setNumberOfWindows(number) {
    this.house.windows = number;
    return this;
  }
  
  build() {
    return this.house;
  }
}

const house = new HouseBuilder()
  .setBuildingType('apartment')
  .setWallMaterial('brick')
  .setNumberOfDoors(2)
  .setNumberOfWindows(4)
  .build();

// 使用指挥者
class HouseDirector {
  buildCottage(builder) {
    return builder
      .setBuildingType('cottage')
      .setWallMaterial('wood')
      .setNumberOfDoors(2)
      .setNumberOfWindows(8)
      .build();
  }
  
  buildApartment(builder) {
    return builder
      .setBuildingType('apartment')
      .setWallMaterial('concrete')
      .setNumberOfDoors(1)
      .setNumberOfWindows(4)
      .build();
  }
}

const director = new HouseDirector();
const cottage = director.buildCottage(new HouseBuilder());

2.4 原型模式

原型模式基于现有对象创建新对象,而不是从头构建。

// ES5 方式
const carPrototype = {
  init: function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    return this;
  },
  
  getInfo: function() {
    return `${this.make} ${this.model} (${this.year})`;
  }
};

const car1 = Object.create(carPrototype).init('Toyota', 'Camry', 2020);
const car2 = Object.create(carPrototype).init('Honda', 'Accord', 2022);

// 使用类
class Car {
  constructor(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
  }
  
  getInfo() {
    return `${this.make} ${this.model} (${this.year})`;
  }
  
  clone() {
    return new Car(this.make, this.model, this.year);
  }
}

const tesla = new Car('Tesla', 'Model S', 2020);
const clonedTesla = tesla.clone();
clonedTesla.year = 2021;

3. 结构型设计模式

结构型设计模式关注类和对象的组合,形成更大的结构。

3.1 适配器模式

适配器模式使接口不兼容的类能一起工作。

// 旧接口
class OldCalculator {
  constructor() {
    this.operations = function(term1, term2, operation) {
      switch(operation) {
        case 'add':
          return term1 + term2;
        case 'sub':
          return term1 - term2;
        default:
          return NaN;
      }
    };
  }
}

// 新接口
class NewCalculator {
  constructor() {
    this.add = function(term1, term2) {
      return term1 + term2;
    };
    this.sub = function(term1, term2) {
      return term1 - term2;
    };
  }
}

// 适配器
class CalculatorAdapter {
  constructor() {
    const newCalc = new NewCalculator();
    
    this.operations = function(term1, term2, operation) {
      switch(operation) {
        case 'add':
          return newCalc.add(term1, term2);
        case 'sub':
          return newCalc.sub(term1, term2);
        default:
          return NaN;
      }
    };
  }
}

// 客户端代码使用旧接口
const oldCalc = new OldCalculator();
console.log(oldCalc.operations(10, 5, 'add')); // 15

// 适配新接口
const adaptedCalc = new CalculatorAdapter();
console.log(adaptedCalc.operations(10, 5, 'add')); // 15

3.2 装饰器模式

装饰器模式动态地向对象添加新功能,而不改变其原有结构。

// 基础组件
class Coffee {
  cost() {
    return 5;
  }
  
  description() {
    return 'Plain coffee';
  }
}

// 装饰器
class MilkDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
  
  cost() {
    return this.coffee.cost() + 1;
  }
  
  description() {
    return `${this.coffee.description()} with milk`;
  }
}

class SugarDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
  
  cost() {
    return this.coffee.cost() + 0.5;
  }
  
  description() {
    return `${this.coffee.description()} with sugar`;
  }
}

// 使用
let coffee = new Coffee();
console.log(coffee.description()); // "Plain coffee"
console.log(coffee.cost()); // 5

coffee = new MilkDecorator(coffee);
console.log(coffee.description()); // "Plain coffee with milk"
console.log(coffee.cost()); // 6

coffee = new SugarDecorator(coffee);
console.log(coffee.description()); // "Plain coffee with milk with sugar"
console.log(coffee.cost()); // 6.5

// JavaScript 装饰器(提案)
function readonly(target, name, descriptor) {
  descriptor.writable = false;
  return descriptor;
}

class User {
  @readonly
  username() {
    return 'default';
  }
}

3.3 代理模式

代理模式为另一个对象提供替代或占位符,以控制对原始对象的访问。

// 真实主题
class RealImage {
  constructor(filename) {
    this.filename = filename;
    this.loadFromDisk();
  }
  
  loadFromDisk() {
    console.log(`Loading ${this.filename} from disk`);
  }
  
  display() {
    console.log(`Displaying ${this.filename}`);
  }
}

// 代理
class ProxyImage {
  constructor(filename) {
    this.filename = filename;
    this.realImage = null;
  }
  
  display() {
    if (!this.realImage) {
      this.realImage = new RealImage(this.filename);
    }
    this.realImage.display();
  }
}

// 客户端
const image = new ProxyImage('high-res-photo.jpg');
// 没有加载图像
console.log('Image object created');

// 加载并显示图像
image.display();

// 再次显示(不会重新加载)
image.display();

3.4 组合模式

组合模式将对象组合成树状结构,表示"部分-整体"层次结构。

// 组件接口
class UIComponent {
  constructor(name) {
    this.name = name;
  }
  
  render() {
    throw new Error('Render method must be implemented');
  }
  
  getComponentSize() {
    throw new Error('getComponentSize method must be implemented');
  }
}

// 叶子组件
class Button extends UIComponent {
  constructor(name) {
    super(name);
  }
  
  render() {
    console.log(`Rendering Button: ${this.name}`);
  }
  
  getComponentSize() {
    return 1;
  }
}

class Input extends UIComponent {
  constructor(name) {
    super(name);
  }
  
  render() {
    console.log(`Rendering Input: ${this.name}`);
  }
  
  getComponentSize() {
    return 1;
  }
}

// 容器组件
class Form extends UIComponent {
  constructor(name) {
    super(name);
    this.components = [];
  }
  
  add(component) {
    this.components.push(component);
  }
  
  remove(component) {
    const index = this.components.indexOf(component);
    if (index !== -1) {
      this.components.splice(index, 1);
    }
  }
  
  render() {
    console.log(`Rendering Form: ${this.name}`);
    this.components.forEach(component => component.render());
  }
  
  getComponentSize() {
    return this.components.reduce((size, component) => {
      return size + component.getComponentSize();
    }, 0);
  }
}

// 客户端代码
const loginForm = new Form('Login Form');
loginForm.add(new Input('Username'));
loginForm.add(new Input('Password'));
loginForm.add(new Button('Submit'));

const registrationForm = new Form('Registration Form');
registrationForm.add(new Input('Name'));
registrationForm.add(new Input('Email'));
registrationForm.add(new Button('Register'));

const mainForm = new Form('Main Form');
mainForm.add(loginForm);
mainForm.add(registrationForm);

// 渲染整个 UI 树
mainForm.render();
console.log(`Total components: ${mainForm.getComponentSize()}`);

4. 行为型设计模式

行为型设计模式关注对象之间的通信和职责分配。

4.1 观察者模式

观察者模式定义对象间的一对多依赖关系,使一个对象改变时,所有依赖它的对象都得到通知。

// 主题
class Subject {
  constructor() {
    this.observers = [];
  }
  
  subscribe(observer) {
    this.observers.push(observer);
  }
  
  unsubscribe(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }
  
  notify(data) {
    this.observers.forEach(observer => observer.update(data));
  }
}

// 观察者
class Observer {
  constructor(name) {
    this.name = name;
  }
  
  update(data) {
    console.log(`${this.name} received: ${data}`);
  }
}

// 使用
const subject = new Subject();

const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');

subject.subscribe(observer1);
subject.subscribe(observer2);

subject.notify('Hello World!');
// "Observer 1 received: Hello World!"
// "Observer 2 received: Hello World!"

subject.unsubscribe(observer1);
subject.notify('Hello Again!');
// "Observer 2 received: Hello Again!"

4.2 策略模式

策略模式定义了一系列算法,将每个算法封装起来,使它们可以互换使用。

// 策略接口
class PaymentStrategy {
  pay(amount) {
    throw new Error('pay method must be implemented');
  }
}

// 具体策略
class CreditCardStrategy extends PaymentStrategy {
  constructor(cardNumber, name, cvv, expiryDate) {
    super();
    this.cardNumber = cardNumber;
    this.name = name;
    this.cvv = cvv;
    this.expiryDate = expiryDate;
  }
  
  pay(amount) {
    console.log(`Paying ${amount} using Credit Card`);
    // 处理信用卡支付逻辑
  }
}

class PayPalStrategy extends PaymentStrategy {
  constructor(email, password) {
    super();
    this.email = email;
    this.password = password;
  }
  
  pay(amount) {
    console.log(`Paying ${amount} using PayPal`);
    // 处理 PayPal 支付逻辑
  }
}

// 上下文
class ShoppingCart {
  constructor() {
    this.items = [];
  }
  
  addItem(item) {
    this.items.push(item);
  }
  
  calculateTotal() {
    return this.items.reduce((total, item) => total + item.price, 0);
  }
  
  checkout(paymentStrategy) {
    const amount = this.calculateTotal();
    paymentStrategy.pay(amount);
  }
}

// 客户端代码
const cart = new ShoppingCart();
cart.addItem({ name: 'Item 1', price: 100 });
cart.addItem({ name: 'Item 2', price: 50 });

// 使用信用卡支付
cart.checkout(new CreditCardStrategy('1234-5678-9012-3456', 'John Doe', '123', '12/25'));

// 使用 PayPal 支付
cart.checkout(new PayPalStrategy('john@example.com', 'password'));

// 使用 JavaScript 函数作为策略
const paymentStrategies = {
  creditCard: function(amount) {
    console.log(`Paying ${amount} using Credit Card`);
  },
  paypal: function(amount) {
    console.log(`Paying ${amount} using PayPal`);
  },
  bitcoin: function(amount) {
    console.log(`Paying ${amount} using Bitcoin`);
  }
};

function processPayment(amount, strategy) {
  return paymentStrategies[strategy](amount);
}

processPayment(150, 'creditCard'); // "Paying 150 using Credit Card"
processPayment(150, 'paypal'); // "Paying 150 using PayPal"

4.3 命令模式

命令模式将请求封装为对象,使用者和发送者解耦。

// 命令接口
class Command {
  execute() {
    throw new Error('execute method must be implemented');
  }
  
  undo() {
    throw new Error('undo method must be implemented');
  }
}

// 接收者
class Light {
  constructor() {
    this.isOn = false;
  }
  
  turnOn() {
    this.isOn = true;
    console.log('Light is now ON');
  }
  
  turnOff() {
    this.isOn = false;
    console.log('Light is now OFF');
  }
}

// 具体命令
class TurnOnCommand extends Command {
  constructor(light) {
    super();
    this.light = light;
  }
  
  execute() {
    this.light.turnOn();
  }
  
  undo() {
    this.light.turnOff();
  }
}

class TurnOffCommand extends Command {
  constructor(light) {
    super();
    this.light = light;
  }
  
  execute() {
    this.light.turnOff();
  }
  
  undo() {
    this.light.turnOn();
  }
}

// 调用者
class RemoteControl {
  constructor() {
    this.commands = [];
    this.history = [];
  }
  
  setCommand(slot, command) {
    this.commands[slot] = command;
  }
  
  pressButton(slot) {
    const command = this.commands[slot];
    if (command) {
      command.execute();
      this.history.push(command);
    }
  }
  
  pressUndoButton() {
    const command = this.history.pop();
    if (command) {
      command.undo();
    }
  }
}

// 客户端代码
const light = new Light();
const turnOn = new TurnOnCommand(light);
const turnOff = new TurnOffCommand(light);

const remote = new RemoteControl();
remote.setCommand(0, turnOn);
remote.setCommand(1, turnOff);

remote.pressButton(0); // "Light is now ON"
remote.pressButton(1); // "Light is now OFF"
remote.pressUndoButton(); // "Light is now ON"

4.4 迭代器模式

迭代器模式提供一种顺序访问集合元素的方法,而不暴露内部表示。

// 自定义迭代器
class ArrayIterator {
  constructor(array) {
    this.array = array;
    this.index = 0;
  }
  
  hasNext() {
    return this.index < this.array.length;
  }
  
  next() {
    return this.hasNext() ? this.array[this.index++] : null;
  }
}

// 可迭代集合
class Collection {
  constructor() {
    this.items = [];
  }
  
  addItem(item) {
    this.items.push(item);
  }
  
  getIterator() {
    return new ArrayIterator(this.items);
  }
}

// 使用迭代器
const collection = new Collection();
collection.addItem('Item 1');
collection.addItem('Item 2');
collection.addItem('Item 3');

const iterator = collection.getIterator();
while (iterator.hasNext()) {
  console.log(iterator.next());
}

// ES6 实现迭代器协议和可迭代协议
class NumberRange {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }
  
  // 使对象可迭代
  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    
    // 迭代器对象
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
}

// 使用 for...of 遍历
for (const num of new NumberRange(1, 5)) {
  console.log(num); // 1, 2, 3, 4, 5
}

4.5 中介者模式

中介者模式通过引入中介对象来减少对象之间的直接通信,降低耦合度。

// 中介者
class ChatRoom {
  constructor() {
    this.users = {};
  }
  
  register(user) {
    this.users[user.name] = user;
    user.chatRoom = this;
  }
  
  send(message, from, to) {
    if (to) {
      // 私聊消息
      this.users[to].receive(message, from);
    } else {
      // 广播消息
      for (const key in this.users) {
        if (this.users[key] !== from) {
          this.users[key].receive(message, from);
        }
      }
    }
  }
}

// 同事类
class User {
  constructor(name) {
    this.name = name;
    this.chatRoom = null;
  }
  
  send(message, to) {
    this.chatRoom.send(message, this, to);
  }
  
  receive(message, from) {
    console.log(`${from.name} to ${this.name}: ${message}`);
  }
}

// 使用
const chatRoom = new ChatRoom();

const john = new User('John');
const jane = new User('Jane');
const bob = new User('Bob');

chatRoom.register(john);
chatRoom.register(jane);
chatRoom.register(bob);

john.send('Hi everyone!');
jane.send('Hey John!', 'John');
bob.send('Hello!');

5. 实际应用案例

5.1 表单验证系统

结合了策略模式和装饰器模式。

// 验证策略
const validators = {
  required: (value) => value.trim() !== '' ? null : 'This field is required',
  minLength: (value, min) => value.length >= min ? null : `Must be at least ${min} characters`,
  maxLength: (value, max) => value.length <= max ? null : `Cannot exceed ${max} characters`,
  email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? null : 'Invalid email format',
  pattern: (value, regex) => regex.test(value) ? null : 'Invalid format'
};

// 表单验证器类
class FormValidator {
  constructor() {
    this.validations = {};
  }
  
  // 添加验证规则
  addValidation(field, validations) {
    this.validations[field] = validations;
  }

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

相关文章:

  • 用Java写一个MVCC例子
  • 理解CSS3 的 max/min-content及fit-content等width值
  • 这是一个文章标题
  • 《网络管理》实践环节04:SNMP监控数据采集流程及SNMP协议详细分析
  • 边缘分布的定义与公式详解
  • 探索 OSPF 协议:构建高效网络的基石
  • [蓝桥杯 2024 省 B] 拔河
  • 心有猛虎,细嗅蔷薇
  • Netty之内存池的原理和实战
  • WebStorm中使用live-server插件
  • Ubuntu 安装 MySQL
  • 国产三维皇冠CAD在「工业自动控制系统装置制造」建模教程:千分表指示器
  • vue项目打包里面pubilc里的 tinymce里的js文件问题
  • Linux 驱动中的资源获取与自动管理机制:深入理解与实战
  • iphone各个机型尺寸
  • Java权限修饰符深度解析
  • 【机器学习算法】基于python商品销量数据分析大屏可视化预测系统(完整系统源码+数据库+开发笔记+详细启动教程)✅
  • springboot starter机制,自动装配
  • LangChain-检索系统 (Retrieval)
  • Unity Standard Shader 解析(三)之ForwardBase(简化版)
  • 曰本真人做爰免费网站/外贸平台
  • 邯郸网站建设恋家/搜索引擎营销推广方案
  • 网站套模板教程/网络最有效的推广方法
  • 用群晖如何做公司网站/seo软件优化工具软件
  • 网站被惩罚/新的网络推广方式
  • 可以做水果的团购网站/网站seo排名公司