您的位置:首页 > 游戏 > 手游 > 新手做网页用什么软件_网上开店策划书_seo和sem_推广软文营销案例

新手做网页用什么软件_网上开店策划书_seo和sem_推广软文营销案例

2025/1/11 5:34:01 来源:https://blog.csdn.net/tmacfrank/article/details/144962774  浏览:    关键词:新手做网页用什么软件_网上开店策划书_seo和sem_推广软文营销案例
新手做网页用什么软件_网上开店策划书_seo和sem_推广软文营销案例

介绍 10 种常用的设计模式,包括单例模式、建造者模式、适配器模式、装饰模式、外观模式、组合模式、策略模式、模板方法模式、观察者模式、责任链模式。

1.单例模式

1-1.基本概念

单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

单例模式的好处

单例模式实际上就是通过把构造方法设为 private,把创建对象的权限收回,由类本身进行对象创建,并对外提供访问该对象的方法。

1-2.单例的6种写法

单例模式有6中写法:饿汉/懒汉/懒汉线程安全/DCL/静态内部类/枚举。

1.饿汉式

public class HungrySingleton {private static HungrySingleton instance = new HungrySingleton();private HungrySingleton() {System.out.println("Singleton is created");}public static HungrySingleton getInstance() {return instance;}public static void main(String[] args) {}
}

饿汉式:静态单例对象在声明的时候就直接用 new 指定了对象,特点是:

  • 静态成员在编译时就分配了内存,并在 ClassLoader 加载这个单例类的时候就实例化单例对象,容易产生垃圾对象。即在还不使用这个类的时候就实例化了对象,一旦系统中出现类加载,那么之前实例化过的对象就成为了垃圾对象。(上边的代码,main() 中没有执行任何代码,但是仍然打出了"Singleton is created",说明单例对象在类加载时就已经实例化了。)
  • 依托于类加载机制,饿汉式单例是线程安全的。

2.懒汉式

饿汉式不使用懒加载就可能会重复创建对象,浪费资源,因此产生了懒汉式单例:

class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}

这种懒汉式是线程不安全的,在多线程下这种写法不能保证只有一个 instance 对象。

3.线程安全的懒汉式

class LazySafetySingleton {private static LazySafetySingleton instance;private LazySafetySingleton() {}// 1.方法声明中用 synchronized 关键字public static synchronized LazySafetySingleton getInstance() {if (instance == null) {instance = new LazySafetySingleton();}return instance;}// 2.方法中用同步代码块public static LazySafetySingleton getInstance() {synchronized (LazySafetySingleton.class) {if (instance == null) {instance = new LazySafetySingleton();}}return instance;}
}

以上两种 getInstance() 都能保证线程安全,但是这种方式的效率低。

4.DCL

Double-checked lock,既能保证线程安全,又优化了线程安全的懒汉式效率低的问题:

class DCLSingleton {// volatile 很关键private static volatile DCLSingleton instance;private DCLSingleton() {}private static DCLSingleton getInstance() {// 判断 instance 是否为空,不为空就可以直接返回单例实例对象了,避免不必要的同步if (instance == null) {// 加锁保证线程安全synchronized (DCLSingleton.class) {// 避免一种情况,即如果在加锁之前就有多个线程通过了第一次 instance 对空判断// 其中一个线程获得锁创建了实例化对象,其余阻塞的线程获得锁之后要再进行一次空判断,// 如果没有判断就会再创建一个新的实例化对象,使得单例构造失败!!!if (instance == null) {instance = new DCLSingleton();}}}return instance;}
}

注意:

  1. 这种写法避免了每一次 getInstance() 都要做同步操作。实际上,如果 instance 已经被实例化过,就可以直接返回它的值而不同再去做同步的判断了,这正是第一个 if (instance == null) 判断所做的。
  2. 但是我在自己写这种模式的时候,忘记了把 instance 声明成 volatile 的,这样就会出问题。
    问题的原因是,instance = new DCLSingleton() 这句话不是原子操作,它分为三个部分:
  • 申请堆内存;
  • 调用 DCLSingleton 构造方法;
  • 让 instance 指向分配的堆内存空间(到这一步 instance 才不是 null)

由于 Java 编译器允许处理器乱序执行,因此执行顺序可能是1-2-3也可能是1-3-2,在后者执行完3之后,倘若来了一个线程拿 instance 对象判空当然是非空的,但是由于其还为被初始化(2没执行),这样就会产生错误。

解决的方法就是给 instance 加上 volatile 关键字修饰,禁止在这个对象的操作中进行指令重排的优化,只能按照1-2-3的顺序执行。

5.静态内部类

DCL 还可以优化,就是使用静态内部类的方式。之所以有这种方式,是因为 JVM 给我们提供了两个同步控制的关键字,static 和 final。static 保证被修饰的对象在内存中只有一份,final 修饰的对象被赋值后不能更改,也是线程安全的。也算是利用了 JVM 在进行类加载的时候会保证数据同步。

在内部类中创建单例对象,那么应用如果不使用内部类,内部类就不会加载,这就实现了懒加载:

class StaticInnerSingleton {private static class SingletonHolder {// final 关键字别落下private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();}private StaticInnerSingleton() {}public StaticInnerSingleton getInstance() {return SingletonHolder.INSTANCE;}
}

这就是目前最好的单例类的写法。JVM 本身机制保证了线程安全,并且没有性能缺陷。

6.枚举

枚举的概念是在 Java5 之后才出现的,用枚举写单例是最简单的:

enum EnumSingleton{// 定义一个枚举元素,他就是 Singleton 的一个实例INSTANCE;public void doSomething(){//...}
}

这样写就是线程安全的,后边如果需要添加一些实例方法,注意也要保证线程安全。

1-3.Android 中的单例

1.Application

应用启动的时候,系统会为我们创建一个唯一的 Application 对象用来存储系统中的配置信息。其实 Application 就用到了单例,你可以直接使用系统的 Application,也可以通过继承 Application 自定义一个,需要把名字写到 AndroidManifest 中的 application 标签下。

由于 Application 的生命周期就是整个应用的生命周期,因此可以用来保存一些全局的静态值。

public class AppContext extends Application {private static AppContext instance;private static AppContext getInstance() {return instance;}@Overridepublic void onCreate() {super.onCreate();instance = this;}
}

2.单例模式引起的内存泄漏

因为单例的静态特性使得单例的生命周期和应用的生命周期一样长, 这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。如:

public class AppManager {private static Context mContext;private static class AppManagerHolder {private static final AppManager INSTANCE = new AppManager(mContext);}public AppManager getInstance() {return AppManagerHolder.INSTANCE;}public AppManager(Context context) {// 让单例对象持有ApplicationContext,可以避免传递进来的Activity、Service等一直被单例对象持有而造成内存泄漏mContext = context.getApplicationContext();}
}

一般情况下我们可能会在 AppManager 的构造方法中直接把传进来的 context 赋值给 mContext。这样就会导致 INSTANCE 持有 context 所代表的那个 Activity 或 Service,导致内存泄漏。规避方法就是用 context 获取 ApplicationContext 交给 INSTANCE 持有,二者生命周期一样,不会泄漏。

2.建造者模式

2-1.基本概念与使用

建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离。

当构造一个对象需要很多参数的时候,并且参数的个数或者类型不固定的时候可以使用该模式。核心思想是把一个复杂的对象的构建和展示分离。

Builder模式UML图

注意上图实际上是一个理论化的建造者模式结构图,实际开发中,往往会省略 Director 和 抽象的 Builder 这两个对象,由客户端直接通过 ConcreteBuilder 去构造 Product 元素中的参数。

理论化代码如下:

public class Product {private String partA;private String partB;private String partC;// getters and setters...
}

Product 用来表示一个有很多成员属性的对象,这些属性可以像示例代码那样是基本类型,也可以是复杂的引用类型。

在构建复杂对象的起始阶段,先定义一个包含设置属性方法的抽象类或者接口:

public abstract class Builder {protected Product product = new Product();public abstract void buildPartA();public abstract void buildPartB();public abstract void buildPartC();public Product getResult() {return product;}
}

然后新建一个子类,实现这些抽象方法(在方法中设置属性):

public class ConcreteBuilder extends Builder {@Overridepublic void buildPartA() {}@Overridepublic void buildPartB() {}@Overridepublic void buildPartC() {}
}

新建一个 Director 作为控制 ConcreteBuilder 设置 Product 属性的控制器:

/*** 1.隔离程序员创建复杂对象的过程* 2.控制复杂对象的创建过程(是否需要partA或partB或partC)*/
public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}public Product construct() {// 通过builder来控制建立或不建立某一个属性,这就是控制创建过程builder.buildPartA();//builder.buildPartB();builder.buildPartC();return builder.getResult();}
}

最后在建造者的客户端创建 Director 实例并调用构建方法:

public class BuilderClient {public static void main(String[] args) {Builder builder = new ConcreteBuilder();Director director = new Director(builder);Product product = director.construct();}
}

建造者模式总结

建造者模式优点

建造者模式缺点

2-2.实际运用

AlertDialog、Glide/OKHttp 等开源框架中对一个类的初始化都用到了建造者模式。例如在 AlertDialog 中:

public static class Builder {private final AlertController.AlertParams P;public Builder(Context context, int themeResId) {P = new AlertController.AlertParams(new ContextThemeWrapper(context, resolveDialogTheme(context, themeResId)));}public Context getContext() {return P.mContext;}public Builder setTitle(@StringRes int titleId) {P.mTitle = P.mContext.getText(titleId);return this;}// setters...
}

AlertDialog.Builder 内部类中持有了一个 AlertController.AlertParams 对象 P,它是 Builder 完成工作的关键。在 Builder 的构造方法中就实例化了 P,后续的所有 set 方法都是对 P 中持有的属性进行的设置。在用户使用 Builder 设置好属性之后,在 AlertDialog 创建的时候会调用 installContent() 去把设置的属性展示出来:

	@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mAlert.installContent();}public void installContent(AlertParams params) {params.apply(this);installContent();}public void apply(AlertController dialog) {if (mCustomTitleView != null) {dialog.setCustomTitle(mCustomTitleView);} else {if (mTitle != null) {dialog.setTitle(mTitle);}if (mIcon != null) {dialog.setIcon(mIcon);}if (mIconId != 0) {dialog.setIcon(mIconId);}if (mIconAttrId != 0) {dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));}}if (mMessage != null) {dialog.setMessage(mMessage);}if (mPositiveButtonText != null) {dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,mPositiveButtonListener, null);}if (mNegativeButtonText != null) {dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,mNegativeButtonListener, null);}if (mNeutralButtonText != null) {dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,mNeutralButtonListener, null);}if (mForceInverseBackground) {dialog.setInverseBackgroundForced(true);}// For a list, the client can either supply an array of items or an// adapter or a cursorif ((mItems != null) || (mCursor != null) || (mAdapter != null)) {createListView(dialog);}if (mView != null) {if (mViewSpacingSpecified) {dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,mViewSpacingBottom);} else {dialog.setView(mView);}} else if (mViewLayoutResId != 0) {dialog.setView(mViewLayoutResId);}}

3.适配器模式

将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。

3-1.类适配器

类的适配器模式把适配类的 API 转换成目标类的 API。

类适配器UML图

Adapter 需要继承 Adaptee 并实现 Target 接口。

类适配器总结

3-2.对象适配器

与类的适配器模式一样,对象的适配器模式把被适配的类的 API 转换成目标类的 API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到 Adaptee 类,而是使用委派关系连接到 Adaptee 类。

对象适配器UML图

对象适配器总结

类适配器是 Adapter 继承 Adaptee,对象适配器是 Adapter 持有 Adaptee 的对象。

Target 接口是我们想用的目标接口,它里边有一个 A() 方法。还有一个 Adaptee 类中的 B() 方法也是我们想用的,在不分别创建它们各自对象,而只使用一个对象的前提下,可以考虑继承 Target 类,在子类中持有 Adaptee 的实例(Adaptee 是接口的话可以通过实现这个接口做到同样效果),这样子类就既能使用 A() 也能调用 B() 了。

3-3.实际运用

ListView中的Adapter

ListView 继承自 AbsListView,和 Adapter 的关联都在 AbsListView 中。如 AbsListView 在显示到窗口时回调的 onAttachedToWindow():

	@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();final ViewTreeObserver treeObserver = getViewTreeObserver();treeObserver.addOnTouchModeChangeListener(this);if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {treeObserver.addOnGlobalLayoutListener(this);}if (mAdapter != null && mDataSetObserver == null) {// 在 Adapter 的数据上注册观察者mDataSetObserver = new AdapterDataSetObserver();mAdapter.registerDataSetObserver(mDataSetObserver);// Data may have changed while we were detached. Refresh.mDataChanged = true;mOldItemCount = mItemCount;mItemCount = mAdapter.getCount(); // 从 Adapter 那获取 ItemView 的个数。}}

再比如在 obtainView() 中获取 ItemView:

View obtainView(int position, boolean[] outMetadata) {// Check whether we have a transient state view. Attempt to re-bind the// data and discard the view if we fail.final View transientView = mRecycler.getTransientStateView(position);if (transientView != null) {final LayoutParams params = (LayoutParams) transientView.getLayoutParams();// If the view type hasn't changed, attempt to re-bind the data.if (params.viewType == mAdapter.getItemViewType(position)) {final View updatedView = mAdapter.getView(position, transientView, this);// If we failed to re-bind the data, scrap the obtained view.if (updatedView != transientView) {setItemViewLayoutParams(updatedView, position);mRecycler.addScrapView(updatedView, position);}}outMetadata[0] = true;// Finish the temporary detach started in addScrapView().transientView.dispatchFinishTemporaryDetach();return transientView;}// 复用的 Viewfinal View scrapView = mRecycler.getScrapView(position);// 从 Adapter 的 getView() 获取到的 ItemViewfinal View child = mAdapter.getView(position, scrapView, this);if (scrapView != null) {if (child != scrapView) {// Failed to re-bind the data, return scrap to the heap.mRecycler.addScrapView(scrapView, position);} else if (child.isTemporarilyDetached()) {outMetadata[0] = true;// Finish the temporary detach started in addScrapView().child.dispatchFinishTemporaryDetach();}}return child;
}

4.装饰模式

动态的给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。是一种对象结构型模式。

使用场景:
1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2.当不能采用继承的方式对系统进行扩展(比如final类),或者采用继承不利于系统扩展和维护时(子类数量大)。

装饰模式UML

装饰模式优点

缺点是比继承更容易出错。

实际运用:ContextWrapper

5.外观模式

外观模式概念

外观模式使用场景

外观模式UML
使用外观模式之后 Client 只需要与外观类交互就可以了,不用知道各个模块的具体实现细节以及它们的内部变化。Facade 外观类持有 ModuleA、ModuleB 和 ModuleC 的引用并调用它们的功能方法,当这些方法发生变化时,只需要对外观类进行一些调整(也有可能外观类也不用改)。而 Client 因为持有着外观类的单例对象(外观类采用单例模式)并调用了它提供的一些操作各模块的方法,没有与各个模块直接交互,因此 Client 就不用改变。

外观模式优点

在 Android 中的实际运用:ContextImpl(startActivity方法)

6.组合模式

将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

使用场景:
1.需要表示一个对象整体或部分层次。
2.让客户端能够忽略不同对象层次的变化。

组合模式UML

组合模式优点

缺点:1.方法都是写好的,不好改。。。。。

Android 中的实际运用:ViewGroup、ViewParent、ViewManager。

7.策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。本模式使得算法可独立于使用它的客户而变化。每一个算法都是一个类,然后再用一个管理类负责实现类之间的切换。

策略模式使用场景
用策略模式代替使用 if-else 判断条件,可以减少条件语句产生的硬编码耦合现象。

策略模式UML
Context 持有 Strategy 抽象类或接口的引用,具体使用哪一种策略,是由创建 Context 的客户端决定的。

策略模式的优点:
1.上下文 Context 和具体策略 ConcreteStrategy 是松耦合关系。Context 只需要持有 Strategy 的抽象引用,而不必与具体的某一个 Strategy 打交道。
2.满足开闭原则。倘若再增加一个 ConcreteStrategyD,那么直接在创建 Context 的时候将 ConcreteStrategyD 的引用传进去即可。而不是像 if-else 那样需要更改代码逻辑。

实际运用:Volley 中对于 HttpStack 的设计。

Volley 中的 HttpStack 有两个实现类,HttpClientStack 在 API 9 之前使用,从 9 开始用 HurlStack。在 Volley.java 中用一个抽象的 Network 对象接收 HttpStack 的过程,就是使用了策略模式:

	public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {if (stack == null) {if (Build.VERSION.SDK_INT >= 9) {stack = new HurlStack();} else {// Prior to Gingerbread, HttpUrlConnection was unreliable.// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.htmlstack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));}}// 策略模式,根据 SDK 的不同版本使用不同的 HttpStackNetwork network = new BasicNetwork(stack);}

HttpStack 是一个接口,而 HurlStack 和 HttpClientStack 是其两个实现类,BasicNetwork 持有 HttpStack 引用,相当于策略模式中的 Context。

8.模板方法模式

模板方法时通过定义一个算法骨架,而将算法中的步骤延迟到子类,这样子类就可以复写这些步骤的实现来实现特定的算法。Activity、Fragment 和 AsyncTask 就是采用了这种模式。

模板方法使用场景

模板方法UML

示例代码:

模板方法代码1
需要让子类实现的方法用抽象方法定义(这个例子中每个人的上班方式、工作内容和下班方式都是不同的,需要子类自己实现)。然后有一个方法管理这些抽象方法,控制它们的执行顺序(用 final 修饰这个方法,那么子类就不能继承这个方法,也不能修改这个方法了)。

老板子类

普通员工子类

模板分为抽象模板和具体模板。主要是定义的父类数量和模板数量的区别。
抽象模板定义了一个抽象操作让子类实现。同时定义并实现了一个模板方法,这个模板方法一般是一个具体方法(如示例代码的getUp())。最关键的是它给出了一个顶层逻辑的框架(newDay()),具体业务逻辑在子类中实现。
具体模板实现父类定义的一个或多个抽象方法,每一个具体模板都有多个抽象模板与之对应。

Activity&Fragment 的生命周期其实就是使用了模板方法。AsyncTask 也使用了这种模式:

FutureTask

9.观察者模式

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式使用场景

观察者模式UML
Subject 是被观察者,它持有所有观察它的对象的实例,把这些实例放在一个集合中维护,并且分别用 attach() 和 detach() 添加/删除它的观察者。当 Subject 中发生数据变化时,用 notify() 通知所有观察者。

依据 UML 图,各类代码如下:

public abstract class Subject {List<Observer> observers = new ArrayList<>();public void attach(Observer observer) {observers.add(observer);}public void detach(Observer observer) {observers.remove(observer);}public void notify(String newState){for (Observer observer : observers) {observer.update(newState);}}
}public class ConcreteSubject extends Subject {private String subjectState;public String getState() {return subjectState;}public void setState(String subjectState) {this.subjectState = subjectState;}public void change(String newState) {subjectState = newState;System.out.println(subjectState);notify(subjectState);}
}public interface Observer {void update(String state);
}public class ConcreteObserver implements Observer {@Overridepublic void update(String state) {System.out.println("ConcreteObserver state:" + state);}
}public class Test {public static void main(String[] args) {Observer observer = new ConcreteObserver();// 左边 Subject 就用不了 change()ConcreteSubject subject = new ConcreteSubject();subject.attach(observer);subject.change("I change");}
}

同一个 UML 图还有不同的实现方法,使用 Java 提供的 Observable 和 Observer:

public class TestObservale extends Observable {// 要观察的数据,发生改变时所有被添加的观察者都能收到通知private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;this.setChanged();this.notifyObservers(message);}
}public class TestObserver implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("数据发生了变化:" + ((TestObservale) o).getMessage());}
}

注意:
1.Observable 中采用 Vector 维护观察者,是处于线程安全角度的考虑(被观察者通知观察者数据变化的时刻,又有添加/删除观察者的操作)。
2.也可以用 CopyOnWriteArrayList 替代 Vector,它也是线程安全的。

实际运用:
1.两个 Activity 中的 Fragment 通信(采用回调是一对一,观察者是一对多)。

例如,Button 上设置的 OnClickListener,Button 就是被观察者,OnClickListener 是观察者。

2.多个 Activity 维护同一个数据源。

3.ListView 更新数据的方法 notifyDataChanged()。

BaseAdapter 中持有 DataSetObservable 实例,其 notifyDataSetChanged() 方法内部就调用了DataSetObservable 的 notifyDataChanged()。在 DataSetObservable 中,notifyChanged() 采用了倒叙遍历 Observer 集合的方式,是为了避免其迭代器出现线程安全问题。

DataSetObservable 继承自 Observable,与之前看的 Observer 实现思路相似。

观察者和被观察者是通过 Adapter 中的 setAdapter() 方法关联起来的。

4.RxJava 的核心是观察者模式。

10.责任链模式

一个请求有多个对象来处理,这些对象是一条链,但具体由哪个对象来处理,根据条件判断来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。

责任链使用场景

责任链UML

实际运用:
1.try-catch 语句:多个 catch 语句找到能处理的那个,其他的就不处理了。
2.有序广播:按照广播优先级进行传递。
3.ViewGroup/View 事件分发机制。

事件就是指 MotionEvent 对象。

dispatchTouchEvent():责任链开端。
onInterceptTouchEvent():只有 ViewGroup 才有的方法。
onTouchEvent():返回结果表示是否消耗该事件。

ViewGroup 事件分发流程:
1.判断自身是否需要。如果自身需要的话,onInterceptTouchEvent() 就返回 true,并且把该事件交给 onTouchEvent() 处理;如果不需要,onInterceptTouchEvent() 就返回 false,把事件传递给子 View,交给子 View 的 onTouchEvent() 处理。
2.如果子 View 不需要则调用 ViewGroup 自身的 onTouchEvent()。

ViewGroup的两个小问题
1.遍历所有子 View,事件坐标在哪个子 View 中,就把事件分配给它。
2.多个子 View 重叠时一般分配给最上边的那个,注意是一般情况下。

View的两个小问题
1.View 可以注册很多事件监听器。
2.顺序是:onTouchListener、onTouchEvent、onLongClickListener、onClickListener

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com