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

中国工程建设管理协会网站厦门软件开发工资一般多少

中国工程建设管理协会网站,厦门软件开发工资一般多少,广西建网站,做网站好还是app好文章目录 了解一下常用的设计模式(工厂、包装、关系)导语设计模式辨析系列 工厂篇工厂什么是工厂简单工厂「模式」#xff08;Simple Factory「Pattern」#xff09;简单工厂代码示例#xff1a;简单计算器优点#xff1a;缺点#xff1a; 静态工厂模式特点#xff1a; 工… 文章目录 了解一下常用的设计模式(工厂、包装、关系)导语设计模式辨析系列 工厂篇工厂什么是工厂简单工厂「模式」Simple Factory「Pattern」简单工厂代码示例简单计算器优点缺点 静态工厂模式特点 工厂方法模式Factory Method Pattern什么是工厂方法模式工厂方法模式代码示例简单计算器优点与简单工厂的异同 抽象工厂模式Abstract Factory Pattern什么是抽象工厂模式抽象工厂模式代码示例计算器生产优点缺点与工厂方法模式的异同 拓展总结 包装篇导语装饰模式Decorator Pattern什么是装饰模式装饰者被装饰对象装饰模式代码实例装饰者模式和继承的区别装饰模式的优缺点 什么是适配器模式适用场景适配器模式代码实例:适配器模式优缺点适配器模式的类型类适配器继承被适配者类和目标类对象适配器利用组合的方式将请求传送给被适配者 与装饰者模式的区别 外观模式Facade Pattern什么是外观模式适用场景外观模式代码实例外观模式优缺点与装饰模式、适配器模式的区别 代理模式Proxy Pattern什么是代理模式代理控制访问方式代理模式代码实例:代理模式的优缺点与装饰模式、适配器模式的区别代理模式变体类型简单了解 总结四种设计模式的目的 关系篇导语继承继承关系的潜在问题 桥接模式Bridge Pattern什么是桥接模式桥接模式如何应对变化合成/聚合复用原则CARP桥接模式示意图桥接模式代码实例桥接模式的优缺点 组合模式Composite Pattern什么是组合模式组合、组件、叶节点、枝节点组合模式的分类透明方式安全方式 组合模式代码实例何时使用组合模式组合模式的优缺点 享元模式Flyweight Pattern什么是享元模式享元对象的状态分类内部状态外部状态 享元模式的主要角色享元工厂Flyweight Factory抽象享元类Flyweight具体享元类Concrete Flyweight非享元类Unshared Concrete Flyweight 享元模式代码实例什么时候使用享元模式享元模式的优缺点享元模式的应用 中介者模式Mediator Pattern什么是中介者模式中介者同事类 中介者模式的关系图中介者模式与桥接模式中介者模式代码实例中介者模式的优缺点中介者模式的应用 总结 了解一下常用的设计模式(工厂、包装、关系) 导语 **设计模式Design Pattern**是软件开发过程中一般问题的解决方案是无数面向对象软件开发人员的经验总结对于软件设计开发十分重要。然而由于设计模式种类繁多内容偏理论缺乏开发经验对于相关概念的理解也比较困难同时其中不乏很多类型相似的设计模式更是让对设计模式的学习难上加难。 本篇为了巩固对于设计模式的理解了解不同设计模式的特点。 资料来源如下 设计模式辨析系列 设计模式辨析——工厂篇简单工厂、静态工厂、工厂方法、抽象工厂 对于使用到工厂的设计模式在理解使用场景和概念后只要记住以下几句话就可以确保掌握了。 所以工厂都是用来封装对象的创建所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合工厂帮助我们针对抽象编程而不是针对具体类编程 设计模式辨析——包装篇装饰模式、适配器模式、外观模式、代理模式 记住关于包装篇的四种设计模式的目的 装饰模式将一个对象包装起来以增加新的行为和责任适配器模式将一个对象包装起来以改变其接口外观模式将一群对象包装起来以简化其接口代理模式将一个对象包装起来以控制对它的访问 设计模式辨析——关系篇桥接模式、组合模式、享元模式、中介者模式 桥接模式、组合模式和中介者模式都改变类或对象之间的关系从而达到各自减少对象数量或降低代码复杂度的目的。 桥接模式使用合成/聚合复用原则变继承为聚合**将抽象部分与它的实现部分分离**减少了子类数量降低了代码的耦合度 组合模式用树形结构表示**“部分-整体”**的层次结构来管理对象使得用户可以用统一的接口使用组合结构中的所有对象简化了代码提高了可扩展性 中介者模式使用中介者负责控制和协调一组对象间的交互将多对多的关系转为一对多降低了对象之间的耦合度提升了代码的复用性、可扩展性。 享元模式则主要为了解决内存资源浪费问题通过对对象之间相似部分的抽取利用共享技术减少对象实例。 区分这几种设计模式的关键依旧在于把握目的意图的不同。 工厂篇 工厂 找出会变化的部分把它们从不变的部分分离出来 当软件开发过程中使用接口时代码中往往需要实例化大量的具体类而这些实现大多是由一些条件决定的。对于如何实例化对象这个问题往往考虑用一个单独的类来处理创造实例的过程这个类就是工厂factory。 什么是工厂 针对接口编程不针对实现编程 定义用于封装创建对象的代码负责处理创建对象的细节的类被称为工厂Factory 优点 将创建对象的代码集中在一个对象或方法中避免代码中的重复便于以后的维护 简单工厂「模式」Simple Factory「Pattern」 简单工厂「模式」是对于工厂最基础的应用但它其实不能算作“工厂模式”它不是一个设计模式像是一种编程习惯。 简单工厂代码示例简单计算器 通过代码实现一个简单计算器具有加减乘除的运算功能 public class OperationFactory {public static Operation createOperation(char operator) {Operation operation null;switch (operator) { //可以看到简单工厂将运算类的实例放在工厂类中实现 //通过分支选择具体的实现类case :operation new OperationAdd();break;case -:operation new OperationSub();break;case *:operation new OperationMul();break;case /:operation new OperationDiv();break;default:throw new RuntimeException(unsupported operation);}return operation;} } public class OperationAdd extends Operation {Overridepublic double result() { //具体的操作子类只需要实现具体运算return numberA numberB;}} public class Calculator {public static void main(String[] args) {Operation operation;char operator;operator ;//使用过程中在客户端提供具体实例的参数传入工厂类实现operation OperationFactory.createOperation(operator);operation.numberA 1.2;operation.numberB 2.3;//具体的运算过程客户端不可见System.out.println(operation.result());} }开放—封闭原则对扩展开放对修改关闭 优点 根据客户端的选择条件动态实例化相关的类去除了客户端与具体类的依赖。添加新的类只需要在工厂类中添加新的分支 缺点 不符合“开放—封闭原则”简单工厂中每一次扩展都需要对工厂类进行修改 静态工厂模式 将工厂类中的创建对象的功能定义为静态的就是静态工厂模式它同样不是一种设计模式。 特点 不需要使用创建对象的方法实例化对象不能通过继承来改变创建方法的行为 由于静态工厂与简单工厂的差别不大在此就不详细展开。关于静态工厂模式更多的内容这篇文章中有详细描述「https://zhuanlan.zhihu.com/p/157099580」感兴趣可以了解。 工厂方法模式Factory Method Pattern 什么是工厂方法模式 工厂方法模式定义了一个创建对象的接口让子类决定要实例化的类是哪一个工厂方法把一个类的实例化推迟到其子类 工厂方法模式代码示例简单计算器 通过代码实现一个简单计算器具有加减乘除的运算功能 public interface IFactory { //所有工厂的抽象工厂接口public Operation createOperation(); //创建实例类的方法延迟到工厂子类中实现 } //工厂的具体实现类 class AddFactory implements IFactory {Overridepublic Operation createOperation() { //实现对操作类的实现 return new OperationAdd();} }class SubFactory implements IFactory {Overridepublic Operation createOperation() {return new OperationSub();} }class MulFactory implements IFactory {Overridepublic Operation createOperation() {return new OperationMul();} }class DivFactory implements IFactory {Overridepublic Operation createOperation() {return new OperationDiv();} }public class FactoryClient {public static void main(String[] args) {//由客户端选择实例化的工厂类除法IFactory operFactory new DivFactory();Operation operation operFactory.createOperation(); //进行运算操作operation.numberA 3.4;operation.numberB 4.5;System.out.println(operation.result());} }优点 通过让工厂子类决定应该创建的对象是什么来达到将对象创建的过程封装的目的。针对接口编程不针对实现编程代码更具弹性扩展性更好符合开放-封闭原则客户端决定实例化哪一个工厂来创建类在扩展时不需要修改工厂类解耦合把创建对象的具体实现移到具体的工厂子类在工厂接口类并不需要知道实际创建的对象是哪一个类解耦了客户端中关于超类的代码和子类对象创建代码。 与简单工厂的异同 同 集中封装了对象的创建降低客户端对特定实现的依赖以及与产品对象的耦合 异 简单工厂把有关实例化的全部事情都在工厂类中处理没有抽象工厂类然而工厂方法模式创建了一个框架让工厂子类决定要如何实现。克服了简单工厂违背“开放-封闭原则”的缺点又保持了封装对象创建过程的优点对简单工厂的进一步抽象和推广 抽象工厂模式Abstract Factory Pattern 依赖倒置原则要依赖抽象不要依赖具体的类 避免在OO设计中违反依赖倒置原则的指导方针 变量不可以持有具体类的引用不要让类派生自具体类不要覆盖基类中已实现的方法 什么是抽象工厂模式 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口而不需要指明它们具体的类。 抽象工厂中的每一个方法创建一个具体类实际利用工厂方法实现 抽象工厂模式代码示例计算器生产 假设现在有流水线负责生产计算器按钮并对计算器进行组装、检查计算器按钮的颜色系列有黑色系列、白色系列等需要实现 //按钮工厂 public interface ButtonFactory{ //生产四种不同的运算按钮public AddButton createAddButton();public SubButton createSubButton();public DivButton createDivButton();public MulButton createMulButton(); } /** * 需要提前说明的是WhiteAddButton是AddButton的具体实现类 * 不同的运算按钮并不是同一类代码省略了Button相关类的声明 */ //白色系列按钮工厂 public class WhiteButtonFactory implements ButtonFactory{Overridepublic AddButton createAddButton() {return new WhiteAddButton();}Overridepublic SubButton createAddButton() {return new WhiteSubButton();}Overridepublic DivButton createAddButton() {return new WhiteDivButton();}Overridepublic MulButton createAddButton() {return new WhiteMulButton();} }//黑色系列按钮工厂 public class BlackButtonFactory implements ButtonFactory{Overridepublic AddButton createAddButton() {return new BlackAddButton();}Overridepublic SubButton createAddButton() {return new BlackSubButton();}Overridepublic DivButton createAddButton() {return new BlackDivButton();}Overridepublic MulButton createAddButton() {return new BlackMulButton();} } //计算器类 public class Calculator() {AddButton addButton;DivButton divButton;SubButton subButton;MulButton mulButton;public Calculator(ButtonFactory buttonFactory) {this.buttonFactory buttonFactory;}public void prepare() {addButton buttonFactory.createAddButton();subButton buttonFactory.createSubButton();divButton buttonFactory.createDivButton();mulButton buttonFactory.createMulButton();}//组装、测试方法public void assembly();public void test(); } public abstract class AssemblyLine {//生产方法public Calculator produce(){Calculator calculator;calculator createCalculator();calculator.prepare();calculator.assembly();calculator.test();return calculator;}protected abstract Calculator createCalculator(); } //白色按钮流水线 public class WhiteAssemblyLine extends AssemblyLine {Overrideprotected Calculator createCalculator(){Calculator calculator null;ButtonFactory buttonFactory new WhiteButtonFactory();calculator new Calculator(buttonFactory);return calculator;} } //黑色按钮流水线 public class BlackAssemblyLine extends AssemblyLine {Overrideprotected Calculator createCalculator(String type){Calculator calculator null;ButtonFactory buttonFactory new BlackButtonFactory();calculator new Calculator(buttonFactory);return calculator;} } public class CalculatorClient() {public static void main(String[] args) {//声明流水线AssemblyLine whiteLine new WhiteAssemblyLine();AssemblyLine blackLine new BlackAssemblyLine();//决定生成的计算器实例可以看到系列按钮的创建过程与客户端分离Calculator calculator1 whiteLine.produce();Calculator calculator2 blackcLine.produce();} }需要注意的是由于抽象工厂类的使用场景针对「系列」所以这里代码示例的场景发生了改变涉及类比较多请一定搞清楚。其中抽象工厂类的主要作用是把不同系列的按钮创建封装在了一起因此在改变计算器的按钮系列时我们只需要更换流水线类就好了流水线类在这里其实只是工厂类上的一个封装可以简单理解为更换了工厂类。你可以设想一下要是使用的是简单工厂、工厂方法模式要想实现上述代码示例的功能代码应该怎么写改动按钮系列时需要改动那些地方 优点 易于交换产品系列改变具体工厂类只需要在初始化时进行十分方便就可以使用不同产品配置允许客户使用抽象的接口创建具体的一组产品创建过程与客户端分离降低耦合度 缺点 增加需求时需要改动接口对每一个具体工厂类进行改动较为复杂 与工厂方法模式的异同 同 集中封装了对象的创建降低客户端对特定实现的依赖以及与产品对象的耦合 异 创建对象 工厂方法模式继承 通过工厂子类创建对象客户端只需要知道具体的抽象类型由工厂子类决定具体类型只负责将客户从具体类型中解耦 抽象工厂模式对象的组合 提供用来创建一个产品家族的抽象类这个类型的子类定义产品被创建的方法使用时通过实例化具体工厂类并将工厂类传入针对抽象类型写的代码中把客户从所使用的实际具体产品中解耦 抽象工厂集合了一群相关的产品类而工厂方法只需要创建一个产品。抽象工厂中的每一个方法创建一个具体类实际是利用工厂方法实现 拓展 利用简单工厂改进抽象工厂 减少具体工厂类达到解耦目的 反射抽象工厂 利用依赖注入消除switch的使用 总结 对于使用到工厂的设计模式在理解使用场景和概念后只要记住以下几句话就可以确保掌握了。 所以工厂都是用来封装对象的创建所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合工厂帮助我们针对抽象编程而不是针对具体类编程 包装篇 导语 当你在编写代码时需要扩展一个类的功能或者是当前类的接口不能满足需求时你会选择怎么做。重新编写子类通过继承加入功能修改原有类的接口使其符合现有环境但你会发现这些改动是不完美的它们并不符合面向对象的「开放-关闭原则」。 开放-关闭原则 对扩展开放对修改关闭 在软件设计模式中有一个更好的答案——包装。 下面介绍的四种设计模式都围绕着“包装”展开那么首先先简单了解一下这些设计模式 装饰者模式Decorator Pattern包装另一个对象并提供额外的行为适配器模式Adapter Pattern包装另一个对象并提供不同的接口外观模式Facade Pattern包装许多对象以简化它们的接口代理模式Proxy Pattern包装另一个对象并控制对它的访问 装饰模式Decorator Pattern 当你想要扩展一个类的功能时最直接的方法就是编写一个子类然后在子类中加入新的功能函数。但是这种更改往往会导致很多问题例如想要去掉父类中的一个方法时。这不是一种弹性设计不符合「开放-关闭原则」。装饰模式提供了继承之外的一种新思路。 什么是装饰模式 定义动态地将责任附加到对象上给对象添加额外的职责对于扩展功能来说 装饰者提供了比继承更有弹性的方法。 装饰者可以在所委托的被装饰者的行为之前或之后加上自己的行为达到特定的目的使用装饰者模式的过程中可以使用多个装饰类包装对象数量没有限制客户端可以在运行时有选择地使用装饰功能包装对象。 装饰者被装饰对象 装饰者和被装饰对象需要具有相同的父类装饰者模式用继承达到类型匹配的目的 每个装饰对象的实现与如何使用这个对象分离开每个装饰对象只关心自己的功能不需要关心如何被添加到对象链中。 使用方法将需要实例化的对象传入装饰类中进行包装 http://Java.IO库就是以装饰者模式来编写的 装饰模式代码实例 //Component定义了一个对象接口通过装饰类可以给这些对象动态地添加职责 public abstract class Component {public abstract void operation(); } /** Decorator装饰抽象类继承了Component * 从外类来扩展Component类的功能但对于Component来说 * 是无需知道Decorator的存在的 */ public abstract class Decorator extends Component {protected Component component; //获取被装饰的对象public Component getComponent() {return component;} //设置被装饰的对象public void setComponent(Component component) {this.component component;}Overridepublic void operation() {if (component ! null) {component.operation();}} } //具体装饰类可以为类加入新的行为 class ConcreteDecoratorA extends Decorator {private String addedState;Overridepublic void operation() {// 首先运行原Component的operation()再执行本类的功能如addedState相当于对原Component进行了装饰super.operation();addedState A中的new state ;System.out.println(addedState 具体装饰对象A的操作);} }class ConcreteDecoratorB extends Decorator {Overridepublic void operation() {super.operation();addedBehavior();System.out.println(具体装饰对象B的操作);}public void addedBehavior() {System.out.print(B中的新增行为 );} }class ConcreteDecoratorC extends Decorator {Overridepublic void operation() {super.operation();System.out.println(C没有特殊行为 具体装饰对象C的操作);}} //ConcreteComponent是定义一个具体的对象也可以给这个对象添加一些职责 public class ConcreteComponent extends Component {Overridepublic void operation() {System.out.println(具体对象的操作);}} //装饰模式客户端调用代码 public class DecoratorClient {public static void main(String[] args) {ConcreteComponent concreteComponent new ConcreteComponent();//声明装饰类A、B、CConcreteDecoratorA concreteDecoratorA new ConcreteDecoratorA();ConcreteDecoratorB concreteDecoratorB new ConcreteDecoratorB();ConcreteDecoratorC concreteDecoratorC new ConcreteDecoratorC();//装饰的过程就像是层层包装不断地装饰类包装对象达到添加功能的目的concreteDecoratorA.setComponent(concreteComponent); //装饰类A包装对象concreteDecoratorB.setComponent(concreteDecoratorA); //装饰类B包装装饰类A对象已经被包装在装饰类A中concreteDecoratorC.setComponent(concreteDecoratorB); //装饰类C包装装饰类BconcreteDecoratorC.operation();} }在DecoratorClient中经过装饰类的包装后最终对象关系如下被装饰者concreteComponent包装在装饰类中同时具有了各个装饰类附加的方法和行为 各个对象的包装关系 装饰者模式和继承的区别 继承设计子类是在编译时静态决定的通过组合的做法扩展对象可以在运行时动态地进行扩展装饰者模式通过组合和委托可以在运行时动态地为对象加上新的行为 装饰模式的优缺点 优点 把类中的装饰功能从类中搬移简化原有类有效地把类的核心职责和装饰功能区分开去除相关类中重复的装饰逻辑 缺点 装饰者模式常常造成设计中出现大量的小类数据太多可能会使程序变得复杂对使用API的程序员产生困扰装饰者在实例化组件时除了实例化组件还要将组件包装进装饰者中会增加代码复杂度克服这一缺点通过工厂模式和生成器模式对实例化部分代码进行封装 什么是适配器模式 定义适配器模式将一个类的接口转换成客户期望的另一个接口适配器让原本接口不兼容的类可以一起工作。 适配器通过使用对象组合以修改的接口包装被适配者。 适配器把被适配者的接口转换为适配者的接口。 适用场景 需要使用一个现有类而其接口并不符合需求的时候当两个类做的事情相同或相似但具有不同接口时可以使用适配器模式统一接口 适配器模式代码实例: //客户所期待的接口 public abstract class Target {public void request() {System.out.println(普通请求);} }//适配器类通过在内部包装一个Adaptee对象把原接口转换成目标接口 public class Adapter extends Target {//内部的Adaptee对象private Adaptee adaptee new Adaptee();Overridepublic void request() { //适配器类提供的客户端需要的接口adaptee.specificRequest();} }//需要适配的类 public class Adaptee {public void specificRequest() {System.out.println(特殊的请求);}}//适配器客户端 public class AdapterClient {public static void main(String[] args) {Target target;target new Adapter(); //直接调用适配器类内部包装了Adapteetarget.request();} }适配器模式优缺点 优点 不需要进行代码的大量改动通过添加一个适配器类将改变封装在类中满足新的需求让客户和实现的接口/适配器解耦 缺点 导致更多的“包装”类用以处理和其他组件的沟通会导致复杂度和开发时间的增加并降低运行时的性能太多的类耦合在一起会提高维护成本和降低代码的可理解性 适配器模式只有在碰到无法改变原有设计和代码的情况才考虑在设计开发的过程中应该预先预防接口不匹配的问题发生当出现有小的接口不统一时应及时重构避免问题的扩大 适配器模式的类型 类适配器继承被适配者类和目标类 类适配器通过多重继承对一个接口与另一个接口进行匹配 优点 由于适配器类是适配者类的子类因此可以再适配器类中置换一些适配者的方法使得适配器的灵活性更强。 缺点 对于Java、C#等不支持多重继承的语言一次最多只能适配一个适配者类目标抽象类只能为接口不能为类其使用有一定的局限性不能将一个适配者类和他的子类同时适配到目标接口。 对象适配器利用组合的方式将请求传送给被适配者 可以适配某个类及其任何子类 优点 把多个不同的适配者适配到同一个目标也就是说同一个适配器可以把适配者类和他的子类都适配到目标接口。 缺点 把多个不同的适配者适配到同一个目标也就是说同一个适配器可以把适配者类和他的子类都适配到目标接口。 与装饰者模式的区别 装饰者模式需要添加新的功能时使用 加入新功能到类中而无需改变现有代码 适配器模式需要转换接口时使用 允许用户使用新的库和子集合而无需改变原有代码 最少知识原则(Least Knowledge Principle)又名迪米特法则(Law of Demeter) 每个单元对其他单元只拥有有限的知识只了解与当前单元紧密联系的单元即只和你的密友谈话 方针只调用属于以下范围的方法 该对象本身被当做方法的参数而传递进来的对象此方法所创建或实例化的任何对象对象的任何组件 外观模式Facade Pattern 当有很多复杂的接口需要使用时通过一个类来将复杂的逻辑封装在内并提供简单的统一接口可以很好的提高代码的可读性降低程序复杂度。 外观模式就是这样的一个类不过它并没有“封装”子系统。当你需要简化并统一一个很大的接口或一群复杂的接口时可以使用外观模式。 什么是外观模式 定义外观模式提供了一个统一的接口用来访问子系统中的一组接口。此模式定义了一个高层接口使得子系统更容易使用。 可以创建多个外观 适用场景 通过使用外观模式在数据访问层、业务逻辑层和表示层的层与层之间建立“外观”降低耦合度 外观模式代码实例 //“系统”接口只是标记接口暂无任何意义 public interface SystemInterface {} //子系统类 class SubSystemOne implements SystemInterface {public void methodOne() {System.out.println(子系统方法一);} }class SubSystemTwo implements SystemInterface {public void methodTwo() {System.out.println(子系统方法二);} }class SubSystemThree implements SystemInterface {public void methodThree() {System.out.println(子系统方法三);} }class SubSystemFour implements SystemInterface {public void methodFour() {System.out.println(子系统方法四);} } //外观类包括了所有的子系统的方法或属性进行组合以备外界调用 public class Facade { //子系统SubSystemOne subSystemOne;SubSystemTwo subSystemTwo;SubSystemThree subSystemThree;SubSystemFour subSystemFour;public Facade() {subSystemOne new SubSystemOne();subSystemTwo new SubSystemTwo();subSystemThree new SubSystemThree();subSystemFour new SubSystemFour();} //外观类提供的统一接口public void methodA() {System.out.println(方法组A:);subSystemOne.methodOne();subSystemTwo.methodTwo();subSystemFour.methodFour();}public void methodB() {System.out.println(方法组B:);subSystemThree.methodThree();subSystemFour.methodFour();} } //外观类客户端 public class FacadeClient {public static void main(String[] args) {// 由于Facade的作用客户端可以根本不知道四个子系统的存在Facade facade new Facade();facade.methodA();facade.methodB();} }维护一个遗留的大型系统时可能这个系统已经非常难以维护和扩展了此时可以为新系统开发一个外观Facade类来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口让新系统与Facade对象交互Facade与遗留代码交互所有复杂的工作。 外观模式优缺点 优点 将客户端从子系统中解耦客户端代码面向接口编写若要修改子系统的组件时只需要改动外观类就可以通过实现一个提供更合理的接口的外观类隐藏复杂子系统背后的逻辑提供一个方便使用的接口没有“封装”子系统的类只提供简化接口子系统的类依然可以被调用。在提供简化接口的同时将系统完整的功能暴露出来以供需要的人使用。遵循「最少知识原则」 缺点 在不引入抽象外观类的情况下增加新的子系统可能需要修改外观类或客户端的源代码违背了「开放-关闭原则」 与装饰模式、适配器模式的区别 装饰者不改变接口但加入责任适配器将一个接口转成另一个接口改变接口使其符合客户期望外观让接口更简单提供子系统的一个简化接口 代理模式Proxy Pattern 代理从字面意思理解就是代理他人的职务。在计算机中代理常用来控制和管理访问如代理服务器可以作为中转站代理网络用户去获取网络信息。 什么是代理模式 定义代理模式为另一个对象提供一个替身或占位符以便控制客户对对象的访问 使用代理模式创建代表让代表对象控制某对象的访问被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象 代理控制访问方式 远程代理控制访问远程对象为一个对象在不同的地理空间提供局部代表虚拟代理控制访问创建开销大的资源通过代理替代实例化需要很长时间的真实对象网页加载时的图片框保护代理基于权限控制对资源的访问 代理模式代码实例: 这里的代理只是简单的示例实际上的代理往往在上面提到的几个场景远程、虚拟、保护中使用用来控制和管理访问 //接口类定义真实实体类与代理类共用的接口 public interface Subject {public void request(); } //实体类 public class RealSubject implements Subject {Overridepublic void request() {System.out.println(真实对象的请求);} } //代理类 public class Proxy implements Subject {// 保存一个引用使得代理可以访问真实实体Subject subject;public Proxy() {subject new RealSubject();}Overridepublic void request() {subject.request();}} //代理客户端 public class ProxyClient {public static void main(String[] args) {Proxy proxy new Proxy();proxy.request();} }代理模式的优缺点 优点 代理模式在访问对象时引入一定程度的间接性这种间接性可以附加多种用途代理模式在客户端与目标对象之间起中介作用可以保护目标对象使得客户端与目标对象分离在一定程度上降低了耦合 缺点 增加了系统的复杂度客户端只能够看到代理类会出现大量的重复代码。 与装饰模式、适配器模式的区别 装饰者为对象增加行为而代理控制对象的访问代理和适配器都挡在其他对象前面负责将请求转发给它们适配器会改变对象适配的接口而代理则实现相同的接口 代理模式变体类型简单了解 防火墙代理Firewal Proxy控制网络资源的访问保护主题免于“坏客户”的侵害智能引用代理Smart Reference Proxy当主题被引用时进行额外的动作代理处理另一些事儿。例如计算一个对象被引用的次数缓存代理Caching Proxy为开销大的运算结果提供暂时存储它也允许多个客户共享结果以减少计算或网络延迟同步代理Synchronization Proxy在多线程的情况下为主题提供安全的访问复杂隐藏代理Complexity Hiding Proxy用来隐藏一个类的复杂集合的复杂度并进行访问控制有时候也称为外观代理Facade Proxy写入时复制代理Copy-On-Write Proxy用来控制对象的复制方法是延迟对象的复制直到客户真的需要为止这是虚拟代理的变体。 总结 对于装饰模式、适配器模式、外观模式和代理模式他们彼此之间都有相似之处例如四种都对对象进行了包装适配器模式和外观模式都提供了接口代理模式和装饰模式都可能会引入新功能… 但其实区分这几种设计模式重点不在于如何包装类包装类的个数、是否添加新功能重点在于不同设计模式的目的意图不同 四种设计模式的目的 装饰模式将一个对象包装起来以增加新的行为和责任 不改变接口但加入责任 适配器模式将一个对象包装起来以改变其接口 将一个接口转成另一个接口改变接口使其符合客户期望 外观模式将一群对象包装起来以简化其接口 让接口更简单提供子系统的一个简化接口 代理模式将一个对象包装起来以控制对它的访问 控制和管理对对象的访问 把握了以上几点也就记住了四种设计模式的本质区别相信对于每个设计模式适用场景也能有更深的理解。 关系篇 导语 在上部分中针对继承在编译时静态决定类可扩展性差等问题装饰模式提供了比继承更弹性的方法来为类添加功能函数这部分进一步讨论继承的潜在问题重点着眼于类和对象之间的关系。桥接模式、组合模式和享元模式都属于 「结构型设计模式」 而中介者模式属于 「行为型设计模式」 为了更好的几种模式对比而放在这一部分中尽管关系篇的命名可能不够准确但还是比较能概括这几种设计模式的共同点。 继承 继承作为面向对象的三个基本特征之一是最常见的一种类关系作用如下 子类通过继承父类的特征和行为使得子类对象实例具有父类的属性和方法或子类从父类继承方法使得子类具有父类相同的行为。 优点继承可以使用子类重写父类方法的方式进行扩展提高了代码的复用性并获得了一定的可扩展性 缺点继承的过度使用会导致类的结构过于复杂对象之间关系太多代码难以维护扩展性差。 继承关系的潜在问题 对象的继承关系在编译时静态定义好的无法在运行时改变从父类继承的实现。子类的实现与父类有紧密的依赖关系父类实现中的任何变化都会导致子类的变化复用子类时继承的实现可能不适合解决新的问题这时父类必须重写或替换这种依赖关系限制了灵活性和复用性 子类和父类之间的关系是一种高耦合关系。 桥接模式Bridge Pattern 一个父类可以通过子类实现多种变化。在类变化较为复杂的情况下只使用继承会造成大量的类增加不能满足开放-封闭原则。继承是一种强耦合的结构我们的设计目标是找到一个弱耦合、松耦合的结构来表示抽象类和实现之间的关系这个设计模式就是桥接模式。 桥接模式通过解耦类不同方向的变化使用对象组合的方式把两个角色之间继承关系改为组合关系从而使得两者应对各自独立的变化。 什么是桥接模式 顾名思义「桥」 起到连接作用在桥接模式中通过 「桥」 连接的抽象和实现两个独立的结构这两个部分可以以继承的方式独立扩展、变化而不相互影响。 定义桥接模式将抽象部分与它的实现部分分离使它们都可以独立地变化。 抽象与实现分离不是说抽象类和派生类分离实现指的是抽象类和它的派生类用来实现自己的对象实现可以有多角度方向分类 桥接模式的核心意图将每一种分类的实现分离出来让他们独立变化减少它们之间的耦合每种实现的变化不会影响其他实现从而达到应对变化的目的。 桥接模式如何应对变化 找出变化封装之优先使用对象聚集而不是继承即合成/聚合复用原则 合成/聚合复用原则CARP 尽量使用合成/聚合尽量不要使用类继承 合成Composition表示一种强“拥有”关系体现了严格的部分和整体的关系部分和整体的生命周期一样 聚合Aggregation表示一种弱“拥有”关系体现A对象包含B对象但B对象不是A对象的一部分 合成和聚类都是关联的特殊种类。 好处 有限使用对象的合成/聚合将有助于保持每个类被封装并被集中在单个任务上。这样类和类继承层次都可以保持较小规模不至于增长过多而不可控制。 桥接模式示意图 假设现在有一个书本生产系统生产的书本有Book1、Book2两种类型黄色和绿色两种不同颜色现有抽象类Book若仅使用继承那么就需要如下图示的四种子类才可以满足需求。 若要添加书本类型或颜色类型均需要声明对子类进行新的扩展需要的子类数将呈现爆炸性增长代码复杂度将不断增加。 仅使用继承 而使用桥接模式可以将书本类型抽象和颜色类型实现两部分分离开来改继承为组合扩展和变化将在两个独立角度中进行不再需要通过添加子类的方式实现扩展。 桥接模式 颜色相关的代码将被抽取到颜色类中并通过在书本类中添加指向颜色对象的成员变量将书本和颜色两部分连接起来。使用桥接模式后新增颜色将不会对现有的形状类产生影响反之新增形状也不会对现有的颜色类产生影响新增功能或方法都只需要扩展类即可不需要修改现有类符合“开放-封闭”原则。 桥接模式代码实例 public abstract class Abstraction {protected Implementor implementor;// 桥接模式的关键使得Abstraction聚合Implementorprivate String name;public Abstraction(String name) {this.setName(name);}//抽象类所聚合的实现类public void setImplementor(Implementor implementor) {this.implementor implementor;}//相关方法public void operation() {System.out.print(Abstraction- this.getName() : );implementor.operation();}public String getName() {return name;}public void setName(String name) {this.name name;} } //抽象实现类A class AbstractionA extends Abstraction {public AbstractionA(String name) {super(name);}Overridepublic void operation() {super.operation();} } //抽象实现类B class AbstractionB extends Abstraction public AbstractionB(String name) {super(name);}Overridepublic void operation() {super.operation();} } public abstract class Implementor {public abstract void operation(); }class ConcreteImplemtorA extends Implementor {Overridepublic void operation() {System.out.println(ConcreteImplemtorA的方法执行);} }class ConcreteImplemtorB extends Implementor {Overridepublic void operation() {System.out.println(ConcreteImplemtorB的方法执行);} } //客户端 public class BridgeClient {public static void main(String[] args) {Abstraction a new AbstractionA(A);//抽象类A实例a.setImplementor(new ConcreteImplemtorA());//设置包含的具体实现类a.operation();a.setImplementor(new ConcreteImplemtorB());a.operation();Abstraction b new AbstractionB(B);//抽象类B实例b.setImplementor(new ConcreteImplemtorA());b.operation();b.setImplementor(new ConcreteImplemtorB());b.operation();} }桥接模式的优缺点 优点 实现了抽象和实现的分离减少了它们之间的耦合多角度分类实现对象可以降低项目的复杂度和类之间的关系不同角度之间不会相互影响新增功能或方法都只需要扩展类即可不需要修改现有类 符合“开放-封闭”原则 提高了类的可扩展性 缺点 桥接模式的引入会增加系统的复杂度增加了代码的理解和设计难度桥接模式的使用范围有一定局限性需要识别出系统中两个或多个独立变化的维度才能使用。 组合模式Composite Pattern 什么是组合模式 定义将对象组合成树形结构以表示 “部分-整体” 的层次结构组合模式能让用户以一致的方法处理单个对象和组合对象。 使用树形结构管理对象能够在单个对象之间和组合对象之间游走基本对象可以被组合成更复杂的组合对象组合对象又可以被组合代码中的所有使用基本对象都可以使用组合对象 组合模式让我们能用树形方式创建对象的结构树里面包含了组合以及个别的对象。任何用到基本对象的地方都可以使用组合对象客户可以一致地使用组合结构和单个对象。 组合、组件、叶节点、枝节点 组合由组件构成组合结构中的任意对象称为组件组件有两种类型 叶节点元素枝节点元素组合类 组合的树形结构 根是顶层的组合往下是枝节点最末端是叶节点 在组合模式中所有的对象都属于同一个类整体与部分可以被一致对待使用组合结构我们能把相同的操作应用到组合和个别对象上在大多数情况下我们可以忽略对象组合和单个对象之间的差别 组合模式的分类 透明方式 在组件接口中声明所有用来管理子对象的方法使子对象叶节点和枝节点对于外界没有区别具备完全一致的行为接口。 透明性组合模式以单一责任设计原则换取“透明性”组件的接口同时包含一些管理子节点和叶节点的操作无论是子节点还是叶节点对用户而言都是透明的 存在的问题 存在叶节点类不具有相关的方法实现没有意义的方法的问题违背了单一职责原则即最少知识原则用户有可能做一些不恰当或没有意义的操作失去一些安全性 安全方式 在组合对象中实现所有用来管理子对象的方法组件类中不声明相关方法客户端调用时需要做出相应的判断 安全性 将责任进行区分放在不同的接口上代码需要通过条件语句等判断处理不同类型的节点失去了透明性但这样的设计比较安全 安全方式符合设计模式的的单一职责原则和接口隔离原则 存在的问题 客户端需要对枝节点和子节点进行区分才能处理不同层次的操作无法依赖抽象违背了设计模式的依赖倒置原则。 总结在实现组合模式时需要根据需要平衡透明性和安全性。 组合模式代码实例 /*** Component为组合中的对象提供统一的接口在适当情况下实现所有类共有接口的默认行为。* 使用组合结构的所有类都继承该类*/ public 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);} // 组合类枝节点用来存储子部件实现了组件接口中的相关操作 public class Composite extends Component {private ListComponent children new ArrayListComponent();public Composite(String name) {super(name);}Overridepublic void add(Component component) {children.add(component);}Overridepublic void remove(Component component) {children.remove(component);}Overridepublic void display(int depth) {// 显示其枝节点名称并对其下级进行遍历System.out.println(StringUtil.repeatableString(-, depth) this.name); for (Component component : children) {component.display(depth 2);}} } //叶节点类组合模式中的最小粒度没有子节点 public class Leaf extends Component {public Leaf(String name) {super(name);}Overridepublic void add(Component component) {System.out.println(cannot add to a leaf);}Overridepublic void remove(Component component) {System.out.println(cannot remove from a leaf);}Overridepublic void display(int depth) {// 通过“-”的数目显示级别System.out.println(StringUtil.repeatableString(-, depth) this.name);}} public class CompositeClient {// 展现了组合结构的构成过程public static void main(String[] args) {// 生成树根根上长出两叶Leaf A和Leaf BComposite root new Composite(root);root.add(new Leaf(Leaf A));root.add(new Leaf(Leaf B));// 根上长出分支Composite X分支上也有两叶Leaf X-A和Leaf X-BComposite compositeX new Composite(Composite X);compositeX.add(new Leaf(Leaf X-A));compositeX.add(new Leaf(Leaf X-B));root.add(compositeX);// 在Composite X上再长出分支Composite X-Y分支上也有两叶Leaf X-Y-A和Leaf X-Y-BComposite compositeXY new Composite(Composite X-Y);compositeXY.add(new Leaf(Leaf X-Y-A));compositeXY.add(new Leaf(Leaf X-Y-B));compositeX.add(compositeXY);// 显示大树的样子root.display(1);} }何时使用组合模式 需求中体现部分与整体层次的结构时希望用户可以忽略组合对象与单个对象的不同统一地使用组合结构中的所有对象时就应该考虑组合模式当程序中有多个对象集合且对象之间有“整体/部分”关系并且想用一致方式处理这些对象时需要组合模式 组合模式的优缺点 优点 用户不需要关心对象是组合对象组合模式可以让用户一致地使用组合结构和单个对象组合模式中叶节点的添加十分方便符合开放-关闭原则便于维护 缺点 叶节点和枝节点都是实现类而不是接口违反了依赖倒置原则组合类的引入提升了设计的复杂度客户端需要花时间理清类之间的层次关系 享元模式Flyweight Pattern 在程序设计中有时需要使用大量对象但使用很多对象会导致的内存开销过大的问题若使用的对象大量都是重复则会造成资源的浪费。享元模式是针对这一问题提出的可以避免大量相似类的开销。 如果这些实例除了几个参数外基本上都是相同的时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面在方法调用时把它们传递进来就可以通过共享大幅度地减少单个实例的数目。 什么是享元模式 运用共享技术有效地支持大量细粒度的对象 本质缓存共享对象降低内存消耗。享元模式属于工厂方法模式的改进 享元对象的状态分类 内部状态 在享元对象内部且不会随环境改变而改变的共享部分 外部状态 随着环境改变而改变不可以共享的状态 享元模式的主要角色 享元工厂Flyweight Factory 用来创建并管理Flyweight对象主要用来确保合理地共享Flyweight当用户请求一个Flyweight时为对象提供一个已创建的实例若不存在则为对象创建一个新的Flyweight实例 抽象享元类Flyweight 所有具体享元类的超类或接口通过这个接口Flyweight可以接受并作用于外部状态 具体享元类Concrete Flyweight 继承Flyweight超类或实现Flyweight接口并为内部状态增加存储空间 非享元类Unshared Concrete Flyweight 指不需要共享的Flyweight子类 享元模式代码实例 //享元超类 public abstract class FlyWeight {//接受并作用于外部状态的方法public abstract void operation(int extrinsicState); }class ConcreteFlyWeight extends FlyWeight {Overridepublic void operation(int extrinsicState) {System.out.println(具体FlyWeight extrinsicState);} }class UnsharedConcreteFlyWeight extends FlyWeight {Overridepublic void operation(int extrinsicState) {System.out.println(不共享的具体FlyWeight extrinsicState);} } public class FlyWeightFactory {private HashMapString, FlyWeight flyWeights new HashMapString, FlyWeight();public FlyWeight getFlyWeight(String key) {if (!flyWeights.containsKey(key)) {flyWeights.put(key, new ConcreteFlyWeight());}return flyWeights.get(key);} } public class FlyWeightClient {public static void main(String[] args) {int extrinsicState 22;FlyWeightFactory f new FlyWeightFactory();FlyWeight fx f.getFlyWeight(X);fx.operation(--extrinsicState);FlyWeight fy f.getFlyWeight(Y);fy.operation(--extrinsicState);FlyWeight fz f.getFlyWeight(Z);fz.operation(--extrinsicState);FlyWeight uf new UnsharedConcreteFlyWeight();uf.operation(--extrinsicState);} }什么时候使用享元模式 当一个应用程序使用了大量的对象而这些大量对象产生了巨大的存储开销时应该考虑使用享元模式对象的大多数状态可以使用外部状态删除对象的外部状态可以用相对较少的共享对象取代很多组对象时可以考虑使用享元模式 享元模式的优缺点 优点 使用享元模式中共享对象的使用可以大大减少对象实例总数节约存储开销节约量随着共享状态的增多而增大避免大量细粒度对象的使用又不影响程序运用共享技术有效地支持大量细粒度的对象 缺点 需要维护一个记录了系统已有的所有享元的列表列表也需要耗费资源享元模式会增加系统的复杂度对象共享需要使一些状态外部化会增加程序的逻辑复杂度在程序中有足够多的的对象实例可供共享时才值得使用享元模式 享元模式的应用 NET中字符串string使用了享元模式对于相同的字符串对象使用同一个实例用引用指向的方式实现字符串的内存共享棋类游戏中棋子的颜色是内部状态位置是外部状态以围棋为例使用享元模式仅声明黑白两个棋子实例即可大大减少了内存开销 中介者模式Mediator Pattern 当程序设计中使用大量对象时对象之间的关联关系和系统代码逻辑复杂可扩展性差不利于应对变化。中介者模式通过对对象集体行为的封装来避免这个问题。 什么是中介者模式 定义用一个中介对象来封装一系列的对象交互。中介者使个对象不需要显式地相互引用从而使其耦合松散而且可以独立地改变它们之间的交互。 中介者模式容易在系统中应用也容易误用。在考虑使用中介者模式前一定得考虑好系统设计的合理性 中介者 中介者模式将集体行为封装成一个独立的中介者对象 中介者负责控制和协调一组对象间的交互充当中介是的注重的对象不再相互显式引用对象只知道中介者减少了相互连接的数量。类之间的耦合度降低有利于复用。 同事类 实现业务的具体类各同事类之间的行为均通过中介者进行控制、协调。 中介者模式的关系图 多对象关系图 中介者模式对象关系图 中介者模式使得对象均只需与中介者沟通对象之间的关系转变为星型结构能有效地减少系统的耦合 中介者模式与桥接模式 桥接模式把一个类里面多对多的关系转化为类外部的多个类之间的多对一关系。中介模式把多个类的多对多的关系转化为一对多的关系。从而让代码的职责更为单一更利于复用、扩展、测试。 中介者模式代码实例 //抽象中介类 public abstract class Mediator {public abstract void send(String message, Colleague colleague); } //具体中介类 class ConcreteMediator extends Mediator {// 需要了解所有的具体同事对象private ConcreteColleague1 c1;private ConcreteColleague2 c2;public ConcreteColleague1 getC1() {return c1;}public void setC1(ConcreteColleague1 c1) {this.c1 c1;}public ConcreteColleague2 getC2() {return c2;}public void setC2(ConcreteColleague2 c2) {this.c2 c2;}Overridepublic void send(String message, Colleague colleague) {// 重写发送信息的方法根据对象做出选择判断通知对象if (colleague c1) {c2.notifyMsg(message);} else {c1.notifyMsg(message);}} } //抽象同事类 public abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator mediator;}public abstract void sendMsg(String message);public abstract void notifyMsg(String message); } //具体同事类 class ConcreteColleague1 extends Colleague {public ConcreteColleague1(Mediator mediator) {super(mediator);}Overridepublic void sendMsg(String message) {mediator.send(message, this);}Overridepublic void notifyMsg(String message) {System.out.println(同事1得到消息 message);}}class ConcreteColleague2 extends Colleague {public ConcreteColleague2(Mediator mediator) {super(mediator);}Overridepublic void sendMsg(String message) {mediator.send(message, this);}Overridepublic void notifyMsg(String message) {System.out.println(同事2得到消息 message);} } public class MediatorClient {public static void main(String[] args) {ConcreteMediator concreteMediator new ConcreteMediator();// 让两个具体同事类认识中介者对象ConcreteColleague1 concreteColleague1 new ConcreteColleague1(concreteMediator);ConcreteColleague2 concreteColleague2 new ConcreteColleague2(concreteMediator);// 让中介者认识各个具体同事类对象concreteMediator.setC1(concreteColleague1);concreteMediator.setC2(concreteColleague2);// 具体同事类对象的消息发送都是通过中介者对象转发concreteColleague1.sendMsg(吃过饭了没有);concreteColleague2.sendMsg(没有呢你打算请客);} }中介者模式的优缺点 优点 减少各个对象实例之间的耦合可以独立改变和复用各个与中介者关联的对象实例将对象之间的协作进行抽象将中介作为一个独立的概念封装在对象中这样关注的对象就从对象各自本身的行为转移到它们之间的交互上来也就是站在一个更宏观的角度去看待系统 缺点 中介者模式的优点来自集中控制缺点也来自集中控制 中介者实现了控制集中化将交互复杂性转变为中介者的复杂性当同事类越多中介者的业务就越复杂代码会变得难以管理和改动。 中介者模式的应用 中介者模式一般应用于一组对象以定义良好但复杂的方式进行通信的场合以及想定制一个分布在多个类中的行为而不想生成太多子类的场合 .NET中Windows应用程序的FormWeb网站程序的aspx都使用了中介者模式 总结 桥接模式、组合模式和中介者模式都改变类或对象之间的关系从而达到各自减少对象数量或降低代码复杂度的目的。 桥接模式使用合成/聚合复用原则变继承为聚合 将抽象部分与它的实现部分分离 减少了子类数量降低了代码的耦合度 组合模式用树形结构表示 “部分-整体” 的层次结构来管理对象使得用户可以用统一的接口使用组合结构中的所有对象简化了代码提高了可扩展性 中介者模式使用中介者负责控制和协调一组对象间的交互将多对多的关系转为一对多降低了对象之间的耦合度提升了代码的复用性、可扩展性。 享元模式则主要为了解决内存资源浪费问题通过对对象之间相似部分的抽取利用共享技术减少对象实例。 区分这几种设计模式的关键依旧在于把握目的意图的不同。
http://wiki.neutronadmin.com/news/276862/

相关文章:

  • 怎么做有图有声的网站网站营销网站营销推广
  • 院校建设网站群的原因企业网站开发职责
  • 按揭车在哪个网站可以做贷款有交做拼多多网站的吗
  • 各地残疾人联合会网站建设手机网站开发企业
  • 监控网站模版驻马店住房和城乡建设厅网站
  • wordpress 3d标签插件搜索引擎优化seo专员招聘
  • 博客网站的建设流程wordpress 手机模版
  • 网站排名怎么上去wordpress自动保存远程图片
  • 杭州的设计网站建设icp备案网站更名
  • 网站换空间会影响排名吗制作相册影集app
  • 集团网站建设定制网站建设高端制造股十大龙头
  • 国内做外单的网站有哪些网站建设成本多少
  • 网站后台管理系统摘要怎么写深圳福田做网站公司
  • 网站建设顶层设计怎么做二维码进网站
  • 乐清网站制作公司哪家好西安网站价格
  • 做网站要有策划么网建网络科技有限公司
  • 成都行业网站建设那里好开发app需要什么技术人才
  • 昆山企业网站建设公司外国购物网站大全
  • 贵阳网站建设q479185700惠网站中flash怎么做
  • wordpress企业站模板下载百度站长如何验证网站
  • 个人接单做网站挣钱不好123上网从这里开始
  • 国税网站建设管理沃尔玛网上商城官网
  • 网站公司一站式服务杭州本地网站
  • 网站必须做诚信认证吗wordpress主题付费
  • 天津做网站比较好的公司河南网络优化服务
  • 哈尔滨关键词优化价格英文seo如何优化
  • 临清网站制作郑州教育网站建设
  • 工厂型企业做网站做网站做的好的公司
  • 个人网站做商城会怎样汽车网站建设的目的
  • vps建设网站别人访问不了公司注册资金最低多少