Class-based design has become such an instinct that many developers can't imagine any alternative.

基于类的设计已经成为一种本能,许多开发人员无法想象任何替代方案。

Fortunately for that lot, ES6 adds a class keyword to simplify the syntactical cacophany of working with JavaScript's native prototypes. TypeScript goes further, adding support for access modifiers; interfaces; enums; and a smörgasbård of other classical object-oriented goodies.

幸运的是,ES6添加了一个class关键字来简化使用JavaScript的本机原型的句法模糊性。 TypeScript更进一步,增加了对访问修饰符的支持; 接口; 枚举 以及其他一些经典的面向对象的东西。

Of course, JavaScript doesn't have native classes. Nor does it have native interfaces. Nor does it have native access modifiers. TypeScript does a good job of emulating them, but the illusion can't be total. Keep that in mind, as it's possible to slip past the compile-time checks if you're clever enough.

当然,JavaScript没有本机类。 它也没有本机接口。 它也没有本机访问修饰符。 TypeScript在模拟它们方面做得很好,但是错觉并不能完全解决。 请记住这一点,因为如果您足够聪明,就有可能跳过编译时检查。

After reading this article, you'll be able to:

阅读本文之后,您将能够:

  • Write and design robust classes and interfaces;

    编写和设计健壮的类和接口;
  • Decide whether classes or interfaces are more appropriate for your use case; and

    确定类或接口是否更适合您的用例; 和
  • Article the major principles of object-oriented programming and design.

    文章介绍了面向对象编程和设计的主要原理。

All the code samples for this article are hosted at my GitHub. Clone it down, and run:

本文的所有代码示例都托管在我的GitHub上 。 克隆下来,然后运行:

git checkout Part-2B-OOP_Design_Principle

If you're on Windows, you should be able to run tsc --target ES5. You'll get a frightening bundle of errors, but you can safely ignore them.

如果您使用的是Windows,则应该能够运行tsc --target ES5 。 您会收到一系列令人恐惧的错误,但可以放心地忽略它们。

If you're on Linux or Mac, you'll still run tsc, but you can pipe the errors to nowhere:

如果您使用的是Linux或Mac,则仍将运行tsc ,但可以将错误传递到任何地方:

# Compile all TS files, and silence irrelevant errors.
tsc --target ES5 > /dev/null 2>&1

Either way, you should end up with a folder called built with the transpiled JavaScript.

无论哪种方式,您都应该最终获得一个由已编译JavaScript built的文件夹。

Catch Up: Read From JavaScript to TypeScript Parts I and IIA

追赶 :从JavaScript读到TypeScript Part I和IIA

  • From JavaScript to TypeScript Pt. I: Types & Variables

    从JavaScript到TypeScript Pt。 I:类型和变量
  • From JavaScript to TypeScript, Pt. IIA: Using Classes, Interfaces, & Mixins

    从JavaScript到TypeScript,Pt。 IIA:使用类,接口和混入

类:背景和设计注意事项 ( Classes: Background & Design Considerations )

At the risk of sounding like a broken record: JavaScript does not have classes. It has a class keyword. These are very different things.

听起来有破纪录的危险: JavaScript没有类 。 它有一个class关键字 。 这些是完全不同的东西。

JavaScript uses prototype-based delegation to achieve what Java and C++ accomplish with classes. Even though we might be more comfortable with classical OOP, and even though we might be able to emulate it with prototypes, it will only ever be an emulation.

JavaScript使用基于原型的委托来实现Java和C ++使用类完成的工作。 即使我们对经典的OOP可能更满意,即使我们可以用原型对其进行仿真但它永远只是一种仿真

Under the hood, it's prototypes all the way down.

在引擎盖下,它一直是原型。

That's why it's crucial to understand how JavaScript's classes and prototypes work under the hood. You don't have to like them, but life will be easier if you're familiar with them.

这就是为什么了解JavaScript的类和原型如何在后台运行至关重要。 您不必喜欢它们,但是如果您熟悉它们,生活会更轻松。

抽象和代码重用 (Abstraction & Code Reuse)

DRY code is not necessarily good code, but good code is pretty much always DRY.

DRY代码 不一定是好的代码,但是好的代码几乎总是DRY。

Avoid duplicate code is such a common admonition in modern development that it's hard to write the same code twice without feeling . . . Dirty. And for good reason: If you write your code in one place, and reuse it elsewhere, you'll only have one place to worry about when you debug, maintain, or extend it.

避免重复代码是现代开发中的常见建议,很难两次编写相同的代码。 。 。 脏。 并有充分的理由:如果您将代码编写在一个地方,然后在其他地方重用,则在调试,维护或扩展代码时,只需要担心一个地方。

The basic motivation for classes and objects derives from a similar principle

类和对象的基本动机源自相似的原理

Objects provide a way to associate a data of a certain shape with behavior.

对象提供了一种将特定形状数据行为相关联的方法

Objects provide a way to associate a data of certain shapes with behaviors -- that is, things you'll often want to do with that data. Classes provide a way to desribe those shapes and behaviors in the abstract, making it easy for us to create arbitrariy many similar objects throughout the lifetime of our program.

对象提供了一种将某些形状数据行为相关联的方法 -也就是说,您经常需要对该数据进行处理。 提供了一种抽象描述这些形状和行为的方法,使我们可以在程序的整个生命周期内轻松创建任意相似的对象。

Put another way, a class is like a blueprint: It describes how to build a house. The house is the object itself. Building the house according to the blueprint is analogous to instantiating an object from the class. If we want to change the way the house is built, everywhere it's built, all we have to do is change the blueprint -- not the houses.

换句话说,一个类就像一个蓝图:它描述了如何盖房子。 房子是物体本身。 根据蓝图建造房屋类似于从类中实例化对象。 如果我们想改变房屋的建造方式, 无论房屋到处都是 ,我们要做的就是更改蓝图- 而不是房屋。

We create classes and objects that reflect the structural components of the problems we're solving. This allows us to reason about our programs at a high level of abstraction, which is one of the fundamental aspects of OOP.

我们创建的类和对象反映了我们正在解决的问题的结构性组成部分。 这使我们能够以高度抽象的方式对程序进行推理,这是OOP的基本方面之一。

// user.ts
"use strict";// Blueprint :: This doesn't create users. It just describes them.
class User {constructor (private _name : string,private _email : string) {}get name () : string  { return this._name; }get email () : string { return this._email; }speak () : void { console.log(`I am ${this.name}!`);}// Instantiation :: Create an actual thing that acts as the class describes.
const peleke = new User('Peleke', 'resil.design@gmail.com');
console.log(peleke.name);

An object expresses its behavior through the functions attached to it, called methods, and it holds its data, or state, in instance variables.

对象通过附加到它的函数(称为方法)来表达其行为 ,并将其数据状态保存在实例变量中

In JavaScript, instantiated objects get their own instance variables, but delegate method calls to the class's prototype object. In other words, each object gets its own data, but shares methods with other instances of the class.

在JavaScript中,实例化的对象获得其自己的实例变量,但是将委托方法调用委托给该类的原型对象。 换句话说,每个对象都有自己的数据,但与该类的其他实例共享方法。

That means two things:

这意味着两件事:

  1. If you change methods on the class prototype, all of your instances will behave differently, even if you created them before making the change; and

    如果您在类原型上更改方法,则即使您在进行更改之前创建了它们,所有实例的行为也会有所不同。 和
  2. If you add methods to the class's prototype, all of your instances will be able to call them, even if you created your objects before adding the new methods.

    如果将方法添加到类的原型中,即使您添加新方法之前创建了对象,所有实例都将能够调用它们。
peleke.speak(); // 'I am Peleke!'
peleke.hasOwnProperty('speak'); // false; delegated to User.prototype
peleke.hasOwnProperty('_name'); // true; 'private' property is still technically visibleUser.prototype.speak = null;
try {peleke.speak();
} catch (err) {// Throws TypeError
}

This dynamism is the reason prototypes are so powerful. It's also one of the reasons that we can't perfectly emulate classes.

这种活力是原型如此强大的原因。 这也是我们无法完美模拟类的原因之一。

Unfortunately, declaring methods private to prevent others from overriding it elsewhere doesn't solve the problem -- that keeps you from using it in the first place*.

不幸的是,将方法声明为private以防止其他人在其他地方覆盖它并不能解决问题-导致您一开始就无法使用它*。

You'll also notice that, while you can't read or write private variables, you can still "see" them at runtime. In most popular object-oriented languages, that would throw an access error.

您还将注意到,尽管您无法读取或写入private变量,但仍可以在运行时“查看”它们。 在大多数流行的面向对象语言中,这将引发访问错误。

In the classical model, methods and instance variables are mostly final after instantiation. In other words, under normal circumstances, you can't assign new methods or properties to an object after it's been created.

在经典模型中,方法和实例变量在实例化之后大部分是最终的。 换句话说,在通常情况下,创建对象后,您无法为其分配新的方法或属性。

These are a couple fundamental assumptions of classical design patterns that don't hold in our dynamic environment. Neither is likely to surprise longtime JavaScripters, but they're minor gotchas for folks migrating from other OO languages.

这些是经典设计模式的几个基本假设,这些假设在我们的动态环境中不成立。 长期使用JavaScript的人都不会对这感到惊讶,但是对于从其他OO语言进行迁移的人们来说,它们只是小问题。

* You can return a function from a private getter, though, which is a nifty potential solution to the overwrite problem.

*但是, 您可以从私有getter返回一个函数 ,这对于覆盖问题是一个很不错的解决方案。

封装与实现隐藏 (Encapsulation & Implementation Hiding)

Another advantage of classes is that that they allow us to keep an object's internals hidden from the outside world. We want people to know how to use our objects; we don't want them to know how they work.

类的另一个优点是它们使我们可以使对象的内部结构对外界隐藏。 我们希望人们知道如何使用我们的对象。 我们希望他们知道他们的工作方式。

Exposing as little information about your programs as possible is almost always a good idea. This is called the principle of least privilege, or the Law of Demeter.

尽可能少地公开有关程序的信息几乎总是一个好主意。 这称为最小特权原则 ,或称得墨meter耳法则

This principle implies that our objects should be defined by two things:

这个原则意味着我们的对象应该由两件事来定义:

  1. An Interface An object's interface is what you promise it can do -- in other words, a list of its public methods.

    接口对象的接口就是您所承诺的功能,换句话说,就是其公共方法的列表。
  2. Hidden Implementation Details *. If you ask an object to sort a list of words, whether it use quicksort, mergesort, or O(n) black-magic-sort is irrelevant. All you care about is the sorted list it hands back. *How it gets it to you is none of your business.

    隐藏的实施细节* 如果您要求对象对单词列表进行排序,则它是使用quicksort,mergesort还是O(n)black-magic-sort都是无关紧要的。 您只关心它递回的排序列表。 *如何获得它与您无关。

Separating what an object can do from how it does them is called encapsulaton, and it's one of the cornerstones of good object-oriented design.

分离是什么对象可以从它怎么做他们被称为encapsulaton做的,它是良好的面向对象设计的基石之一。

The reason is that clients who know a method's implementation will write code that relies on that implementation. If the implementation changes, their code breaks, they complain, maintainers have to fix it, and everyone's unhappy.

原因是知道方法实现的客户将编写依赖于该实现的代码。 如果实现发生更改,他们的代码将中断,他们会抱怨,维护人员必须对其进行修复,并且所有人都会感到不满意。

Now, it's clear that library authors have to worry about this, because they literally have clients to support. But the issue is more general than that: Any part of your code that uses one of your objects is a client of that object. If all of your client code depends on the object's implementation, changing your object means changing the code . . . Everywhere.

现在,很明显,库作者必须为此担心,因为他们确实有客户来支持。 但是问题比这更笼统:使用您的一个对象的代码的任何部分都是该对象的客户端 。 如果您所有的客户代码都取决于对象的实现,那么更改对象就意味着更改代码。 。 。 到处。

That largely defeats the purpose of collecting everything into an object in the first place. Ensuring we don't fall into that trap is one of the reasons encapsulation is so essential to good design.

首先,这大大挫败了将所有内容收集到对象中的目的。 确保封装不陷入陷阱是封装对于良好设计至关重要的原因之一。

The interface of a class is the one place where we assert all of the assumptions that a client may make about any instances of the class; the implementation encapsulates details about which no client may make assumptions. ~ Grady Booch, Object Oriented Design & Analysis (pp. 52), emphasis mine

类的接口是一个地方,在这里我们可以声明客户可能对类的任何实例进行的所有假设。 该实现封装了没有客户可以做出假设的细节 。 〜Grady Booch, 面向对象的设计与分析(pp。52) ,重点是我的

To recap, encapsulation buys us:

回顾一下,封装使我们获得了:

1.Safety, by ensuring clients can't muck with an object's guts; and

1. 安全 ,通过确保客户不会弄脏物品的胆量; 和

  1. Flexibility, because clients can't tell if we change internal details as long as our objects still satisfy their interface.

    灵活性 ,因为只要对象仍然满足其接口,客户就无法确定我们是否更改内部细节。

JavaScript has traditionally achieved encapsulation via clever manipulation of closures. TypeScript also provides the private access modifier for properties, which prevents reads or writes at compile-time. It doesn't truly hide the property, however, so you can't trust it to provide airtight encapsulation.'

传统上,JavaScript通过对闭包的巧妙处理来实现封装 。 TypeScript还为属性提供了private访问修饰符,以防止在编译时进行读取或写入。 但是,它并没有真正隐藏属性,因此您不能信任它提供不透气的封装。

交换后端 (Swapping Backends)

Let's imagine we're prototyping an app that fetches definitions for all the words in a user-input sample of Spanish text.

假设我们正在制作一个原型,该应用程序将获取用户输入的西班牙文本样本中所有单词的定义。

We're still figuring out the details, so we expect to be . . . Erm, promiscuous with our back-end, so to speak.

我们仍在弄清楚细节,所以我们希望能做到。 。 。 可以这么说,Erm,与我们的后端混杂在一起。

"use strict";
/* I've omitted some mock implementations from this code, so it won't compile.*   The file, vocabulary_list.ts, on the repository, /does/ compile.*/const config = {
"use strict";const CONFIG = {api : 'wordreference',key : 'API_KEY'
};class VocabularyList {private english_words : Array<string>;constructor (private spanish_words : Array<string>) {this.english_words = [];}fetchWords () : Map<string, string> {return this.parseResponse ( this.makeRequest(CONFIG.api, CONFIG.key) );}private makeRequest (api : string, key : string) : any {const magicalJson = { /* For illustration */ }return magicalJson; }private magicallyGetWord (word : string) : any {// Mock data to please compilerreturn { english_data : 'English language data' }}// This logic is specific to WR's (made-up) response format://    We have to extract the english_entries property from the responseprivate parseResponse (json : any) : Map<string, string> {const translations : Map<string, string> = new Map<string, string>();this.spanish_words.forEach((spanish_word) => {// Get word from API with magic spellconst translation_data = this.magicallyGetWord(spanish_word);// Get data from WORDREFERENCE responseconst english_data = translation_data.english_data;// Get the english_data property -- let's pretend it's also an objecttranslations.set(spanish_word, english_data)});return translations;}
}

Works great, until WordReference shuts down its API (which it kind of did).

效果很好,直到WordReference关闭其API( 确实如此 )。

D'oh.

天啊

After a long stint at the drawing board, we jump ship to Merriam-Webster.

在绘图板上待了很长时间之后,我们跳船去了Merriam-Webster 。

const config = {api : 'merriam-webster',key : 'NEW_API_KEY'
};class VocabularyList {// Nothing new . . . private parseResponse : Array<string> (json : any) {const translations : Map<string, string> = new Map<string, string>();this.spanish_words.forEach((spanish_word) => {// Get word from API with magic spellconst translation_data = this.magicallyGetWord(spanish_word);// Get data from MERRIAM-WEBSTER response -- //   this is the only place we need to make a change!const english_data = getDataFromUglyResponse( translation_data );// Get the english_data property -- let's pretend it's also an objecttranslations.set(spanish_word, english_data)});// Create an information-packed object to send back to the callerreturn buidObject(english_data);}
}

Unfortunately, this API doesn't deliver everything we need in a nice packaged english_data property, so we have to put it together ourselves. That's what getDataFromUglyResponse is for.

不幸的是,此API并没有在打包好的english_data属性中提供我们所需的一切,因此我们必须将其放在一起。 这就是getDataFromUglyResponse目的。

Other parts of our application -- our clients -- use the VocabularyLists's fetchWords method, knowing that it'll hand back a map of translated words.

我们应用程序的其他部分(即客户 )使用VocabularyListsfetchWords方法,因为它知道该方法将返回翻译过的单词的映射。

What they don't know is whether fetchWords is talking to WordReference, Merriam-Webster, or the Oxford English Dictionary. All they need to know is its interface -- that it can fetchWords. They don't know how. That's an implementation detail.

他们不知道fetchWords是与WordReference,Merriam-Webster还是牛津英语词典交谈。 所有他们需要知道的是它的界面- 可以fetchWords 。 他们不知道怎么做。 这是一个实现细节。

If they did know that VocabularyList got its words from WordReference, and had to provide their own logic to parse its response, we'd have at least two problems.

如果他们确实知道VocabularyList是从WordReference获得其单词的,并且必须提供自己的逻辑来解析其响应,那么我们至少会遇到两个问题。

  1. The design would suck, because we'd have to parse JSON in a function that we really should just pass everything it needs; and

    设计很烂,因为我们必须在一个函数中解析JSON,而我们实际上应该只传递它需要的所有内容。 和
  2. Refactoring would suck, because you'd have to write new parsing logic all over the place.

    重构会很麻烦,因为您必须在各处编写新的解析逻辑。

That would be called programming to an implementation, and it's one of the cardinal sins of object-oriented design. It's not just a theoretical no-no, either: This mistake has been responsible for a substantial proportion of my debugging time, as well as that of others. Avoid it like the plague it is.

那将被称为对实现的编程 ,这是面向对象设计的主要缺点之一。 这不仅是理论上的禁忌,也不是:这个错误导致了我和其他人调试时间的很大一部分。 避免它像瘟疫一样。

What we did instead is program to an interface. We wrote our code to expect fetchWords to send us an object with all of the information we need, so we can pick and choose what we want from it.

相反,我们所做的是对接口进行编程 。 我们编写了代码,期望fetchWords向我们发送一个对象,其中包含我们需要的所有信息,因此我们可以从中选择所需的信息。

How VocabularyList gets it to us is irrelevant. Its interface makes a promise; we trust the promise; and so VocabularyList is obligated to keep it.

VocabularyList如何获取给我们是无关紧要的。 它的界面可以保证; 我们相信诺言; 因此VocabularyList有义务保留它。

If the details change, we only worry about it in the code for the class -- nowhere else. This kind of flexibility, and stability of client code in the face of implementation changes, is precisely the point of encapsulation and information hiding.

如果细节发生变化,我们只需要担心该类的代码中的其他问题。 面对实现更改时,客户端代码的这种灵活性和稳定性恰好是封装和信息隐藏的重点。

类关系 ( Class Relationships )

Classes define the shape of the objects they instantiate, as well as their API.

类定义它们实例化的对象的形状以及它们的API。

Classes can also be related to other classes. The most common relationships are:

类也可以与其他类相关。 最常见的关系是:

  • Subclass relationships, and

    子类关系,以及
  • Multiple inheritance.

    多重继承。

JavaScript doesn't support multiple inheritance, but TypeScript's interfaces and mixins scratch a similar itch.

JavaScript不支持多重继承,但是TypeScript的接口和mixins碰到了类似的问题。

子类化和多态 (Subclassing & Polymorphism)

Subclassing is the process of creating a new class that inherits the behavior and data members of another class. A class you create through subclassing is called a child class, or a derived class.

子类化是创建一个新类的过程,该类继承了另一个类的行为和数据成员。 通过子类创建的类称为子类派生类

// raw_fish.ts
class Fish {constructor (public name : string) { }// Pseudo-abstract method :: No-op, unless//   a subclass provides an implementation.cook () : void { }}class SushiFish extends Fish {constructor ( name : string, cooked : boolean = false ) {super(name);}cook () : void { console.log('You don\'t cook a sushi fish!')}}class CookedFish extends Fish {constructor (name : string, cooked : boolean = true) {super (name);}}const tuna = new Fish('Tuna');
const dinner = new CookedFish('Halibut');tuna.cook(); // 'Fish has been cooked!'
dinner.cook(); // 'This fish is already cooked!'

To create a subclass, you use the extends keyword, followed by the base class name. CookedFish is our derived class; Fish is called its superclass.

要创建子类,请使用extends关键字,后跟基类名称。 CookedFish是我们的派生类; Fish被称为超类

Note that we can call cook on our dinner object, even though we didn't define that method explicitly. That's because every method on Fish is available via inheritance. Since a CookedFish is a type of Fish, it should expose the same API.

请注意,即使我们未明确定义该方法,也可以在dinner对象上调用cook 。 这是因为Fish上的每种方法都可以通过继承使用 。 由于CookedFishFish ,因此它应该公开相​​同的API。

It is not, however, obligated to behave identically. Both our SushiFish and our CookedFish classes override their parent's cook method, and so behave differently.

但是,它没有义务表现相同。 我们两个SushiFish和我们CookedFish重写他们的父母的cook方法等不同的表现。

The fact that different classes with unique behavior can share the same interface by relation to a common superclass is called polymorphism.

具有独特行为的不同类可以通过与共同的超类联系而共享同一接口的事实被称为多态性

多重继承 (Multiple Inheritance)

Languages with multiple inheritance allow you to inherit from several parents classes at once.

具有多重继承的语言允许您一次从多个父类继承。

JavaScript doesn't support this, but if it did, it might look like this:

JavaScript不支持此功能,但如果支持,则可能如下所示:

class Wolf extends Canine, Predator {constructor () {// Which superconstructor do we use? Hm . . . super();}
}const wolfie = new Wolf();wolf.howl(); // Canines howl
wofl.hunt(); // Predators hunt

TypeScript doesn't provide sugar for this. But we can achieve similar behavior using either interfaces or mixins.

TypeScript不为此提供糖。 但是我们可以使用接口或混合来实现类似的行为。

接口及其抽象 (Interfaces & Their Abstractions)

An interface describes what you can expect an object to do, but it doesn't define how the object should do it.

接口描述,你可以期望一个对象做什么 ,但它并没有定义对象应该怎么做。

More technically, an interface defines an API that its implementers must expose, but defers the implementation to the implementing classes.

从技术上讲,接口定义了其实现者必须公开的API,但将实现推迟到实现类。

While classes can only inherit from a single superclass, they can implement multiple interfaces. This allows a lot of flexibility in organizing and defining the behavior of our objects.

虽然类只能从单个超类继承,但它们可以实现多个接口。 这为组织和定义对象的行为提供了很大的灵活性。

// printable.tsinterface Identifiable {name : string;identify ();}interface Printable {text : Array<string>;print ();}class Book implements Identifiable, Printable {// Creative implementations here . . . }

Major benefits of interfaces are:

接口的主要优点是:

  • Abstraction. They encourage you to design systems in terms of common behaviors, and discouage you from writing your code with excessive attention to implementation details.

    抽象 。 它们鼓励您根据常见行为来设计系统,并避免过分关注实现细节来阻止编写代码。
  • Flexibility. Interfaces define behavior, but defer the implementation(s) of that behavior to the objects that implement the interface.

    灵活性强 。 接口定义了行为,但是将该行为的实现推迟到实现接口的对象上。
  • Composability. You can implement an arbitrary number of interfaces, allowing you to compose an arbitrary number of APIs into a single object.

    可组合性 。 您可以实现任意数量的接口,从而可以将任意数量的API组合到一个对象中。

One downside is that interfaces can't provide method definitions. This means you'll have to provide implementations in each class that implements the interface.

缺点之一是接口无法提供方法定义。 这意味着您必须在实现该接口的每个类中提供实现。

On one hand, that's largely the point. Deferring implementation details to implementing classes is what makes interfaces so powerful.

一方面,这就是重点。 使实现细节推迟到实现类上是使接口如此强大的原因。

But sometimes, a number of otherwise unrelated classes will implement the same interfaces in exactly the same way.

但是有时,许多其他不相关的类将以完全相同的方式实现相同的接口。

// printable.ts
"use strict";class Book implements Printable, Identifiable {// Shorthand; creats private members automaticallyconstructor ( public name : string,  public text : Array<string>) { }print () : void {console.log(this.text);}// This is the same in both classes!identify () : void {console.log(this.name);}
}class User implements Identifiable {constructor (public name : string) { }// This is the same in both classes!identify () : void {console.log(this.name);}
}

Inheritance is the wrong abstraction for creating largely unrelated classes that act similarly, so extends doesn't make sense. But implements forces us to:

继承是错误的抽象,用于创建行为相似的很大程度上不相关的类,因此extends没有意义。 但是implements迫使我们:

  1. Write the same implementation in multiple places; or

    在多个地方编写相同的实现; 要么
  2. Define the implementation somewhere else, and have both objects refer to it.

    在其他地方定义实现,并让两个对象都引用它。

Crappy design choice, don't you think?

笨拙的设计选择,您不觉得吗?

  1. Neither solution is DRY. If the common behavior changes, you'll have to change it in every implementing class.

    两种解决方案都不是DRY。 如果常见行为发生变化,则必须在每个实现类中进行更改。
  2. Defining a single method somewhere else is a better design choice. But externalizing the implementation somewhere arbitrary largely defeats the organizational purposes of classes and interfaces.

    在其他地方定义单个方法是更好的设计选择。 但是在任意地方将实现外部化在很大程度上破坏了类和接口的组织目的。

Languages like Groovy and Scala have traits, which are effectively interfaces that hold state and implement methods.

诸如Groovy和Scala之类的语言具有traits ,它们是有效的保持状态和实现方法的接口。

TypeScript offers two ways to go about trait-based design:

TypeScript提供了两种基于特征的设计方式:

  1. Abstract classes; or

    抽象类; 要么
  2. Mixins.

    Mixins。

An abstract class lies somewhere between a normal class and an interface.

抽象类位于普通类和接口之间。

Similar to interfaces, you:

与接口类似,您:

  1. . . . Can't instantiate an abstract class. Rather, you must extend from it, and instantiate the derivcd class.

    。 。 。 无法实例化抽象类。 相反,您必须从中extend并实例化派生类。
  2. . . . Can include method signatures without definitions, which derived classes must implement. The only difference to interfaces is that you mark these with the keyword abstract in an abstract class.

    。 。 。 可以包括没有定义的方法签名,派生类必须实现这些方法签名。 与接口的唯一区别是,您在抽象类中用关键字abstract标记了这些接口。

And similar to classes, you:

与类类似,您:

  1. . . . Must use extends to inherit from an abstract class. This means you can only have one abstract parent.

    。 。 。 必须使用extends从抽象类继承。 这意味着您只能有一个抽象父级。
  2. . . . Can provide method implementations, which your derived classes will inherit.

    。 。 。 可以提供派生类将继承的方法实现。

The major difference between abstract classes and traits is that you can extend a single abstract class, whereas you can implement an arbitrary number of traits.

抽象类和特征之间的主要区别在于,您可以扩展单个抽象类,而您可以实现任意数量的特征。

Abstract classes are a good design choice if you're abtracting over several different child structures, which will differ in their implementation of an interface while sharing certain common behaviors.

如果您要抽象几个不同的子结构,则抽象类是一个不错的设计选择。这些子结构在共享某些共同行为的同时,它们在接口的实现上也会有所不同。

If you 've got several mostly unrelated objects implementing an interface identically, though, than a mixin is probably the better solution.

但是,如果您有几个几乎不相关的对象完全相同地实现了一个接口,那么比之类的mixin可能是更好的解决方案。

Mixins vs工具 (Mixins vs Implements)

Thre are few hard and fast rules where design is concerned, but you'll find certain patterns pop up as you do it more. If you're describing behavior:

很少有涉及设计的硬性规则,但是当您执行更多操作时,您会发现某些模式会弹出。 如果您要描述行为:

  • . . . So general that every class implementing it will do so differently, use an ** interface **.

    。 。 。 一般而言,每个实现它的类都将使用**接口**进行不同的操作。
  • . . . General enough that unrelated classes will implement it, but common enough that they'll mostly do so in the same way, use a ** mixin **.

    。 。 。 一般而言,无关的类将实现它,但足够普遍的是,它们将以相同的方式执行此操作,请使用** mixin **。

If the answer to the former is yes, consider an interface. If the answer to the latter is yes, consider mixins. Don't be afraid to ignore the guideline, though; code to a problem, not to a guideline.

如果前者的答案为 ,请考虑使用接口。 如果对后者的回答是肯定的 ,请考虑使用mixins。 但是,不要害怕忽略该准则。 代码来解决问题,而不是准则。

分手评论 (A Parting Comment)

"If you could do Java over again, what would you change?" - "I'd leave out classes." ~ James Gosling, creator of Java, as quoted by Alan Holub, Holub on Patterns

“如果您可以再次使用Java,您将改变什么?” -“我不上课。” 〜Java的创造者James Gosling, Holub在Patterns上的 Alan Holub引用

Never thought I'd hear that one.

没想到我会听到那个。

Turns out that Gosling's point is not that classes are intrinsically bad. Rather, it's that using extends where one should use implements has caused more headaches than anticipated, and that you should be careful creating unnatural class hierarchies.

事实证明,高斯林的观点并不是说班级本质上是不好的。 而是在人们应该使用implements地方使用extends导致了比预期更多的麻烦,并且您应该谨慎创建不自然的类层次结构。

实现继承 (Implementation Inheritance)

Using extends to build new classes is called implementation inheritance, because subclasses created with extends have the same methods as their parents, with the same implementations.

使用extends构建新类称为实现继承 ,因为使用extends创建的子类与其父级具有相同的方法,并具有相同的实现。

This sort of inheritance is natural if you're creating a class that's a special case of another -- say, a FreshwaterFish that extends our Fish class.

如果您创建的类是另一类的特例,则这种继承是很自然的,例如,扩展了Fish类的FreshwaterFish

// freshwater_fish.ts
"use strict";class Fish {constructor (private name : string) { }}class FreshwaterFish extends Fish {constructor (name : string, private salt_tolerant : boolean = false) {super(name);}}

FreshwaterFish class behaves exactly like our Fish class, but holds additional state.

FreshwaterFish类的行为与我们的Fish类完全相同,但是具有其他状态。

More generally, subclassing makes sense when you can use your subclass anywhere you can use your superclass. A program that receives a FreshwaterFish but expects a Fish should remain well-typed throughout, even if it runs differently.

更一般而言,当可以可以使用超类的任何地方使用子类时,子类才有意义。 收到FreshwaterFish但希望Fish在整个过程中都应保持良好类型的程序,即使它的运行方式不同也是如此。

This principle is encoded in the Liskov Substitution Principle. Covering it properly is out of the scope of this article, but take the time to read up on it at some point.

此原理编码在Liskov替代原理中 。 适当地涵盖它不在本文的讨论范围之内,但是请花一些时间仔细阅读它。

接口继承 (Interface Inheritance)

The alternative to implementation inheritance is interface inheritance, or using the implements keyword to declare that an object exposes the API defined by a given interface.

实现继承的替代方法是接口继承 ,或者使用implements关键字声明一个对象公开给定接口定义的API。

Interface inheritance has a number of advantages. It:

接口继承具有许多优点。 它:

  • Loosens coupling between parts of your program;

    松开程序各部分之间的耦合;
  • Eliminates the problem of changes to a superclass breaking subclasses;

    消除了更改超类打破子类的问题;
  • Affords greater flexibility, because any class implementing an interface can implement its API differently.

    提供更大的灵活性,因为任何实现接口的类都可以不同地实现其API。

A class that implements an interface is still said to be a subclass of the interface; and by corollary, an interface can be a supertype.

实现接口的仍然被称为该接口的子类 。 因此,接口可以是超类型。

这个或那个? (This, or That?)

A natural reaction at this point is extreme tenderness at being told to use extends with caution.

在这一点上自然的React是在使用被告知极端压痛extends谨慎。

There are those who would argue that extends is evil. There's a case for that, but I don't think categorical avoidance is a very productive solution.

有些人认为扩展是邪恶的 。 有一个理由,但是我不认为绝对避免是一种非常有效的解决方案。

Subclassing is not inherently worse than any other language feature. Gosling himself admits to using extends more than implements, in spite of the above quip.

子类别在本质上并不比任何其他语言功能都差。 尽管有上述怪癖,高斯林本人也承认使用extends而不是implements

Using subclasses wrong can suck, though, and it's true that a lot of people have a habit of using subclasses where interfaces, mixins, or a different pattern entirely would make more sense. That makes for unmaintanable code, mysterious subclass behavior, and an abundance of senseless class hierarchies.

但是, 错误地使用子类会很烂,而且的确,很多人都有使用子类的习惯,在这些子类中,接口,mixin或其他模式完全有意义。 这导致了不可维护的代码,神秘的子类行为以及大量毫无意义的类层次结构。

The solution isn't to avoid extends: It's to design your code well. Subclasses are easy to understand and easy to implement, which is why they're easy to overuse. That can come back to bite you if you get overzealous.

解决方案不是避免extends :而是设计良好的代码。 子类易于理解且易于实现,这就是为什么它们容易被过度使用的原因。 如果您太过热情,那可能会再次咬住您。

Just remember to always consider your alternatives. As long as you do that, your hierarchies should turn out alright.

只要记住要始终考虑您的替代方案。 只要您这样做,您的层次结构就应该可以了。

结论 (Conclusion)

By now, you should be able to:

现在,您应该能够:

  • Define the Four Fundamentals of OOP: Abstraction, Encapsulation, Polymorphism, and Subclassing;

    定义OOP四个基本原理 :抽象,封装,多态和子类化;
  • Decide whether an interface, class, or mixin is the best abstraction for your problem; and

    确定接口,类或mixin是否是解决问题的最佳抽象; 和
  • Weigh the pros and cons of building systems in terms of implementation or interface inheritance.

    在实现或接口继承方面权衡构建系统的优缺点。

Try reading some code that uses these principles to understand how they work in the real world -- I've been digging through the Angular 2 source, myself.

尝试阅读一些使用这些原理的代码,以了解它们在现实世界中的工作方式-我一直在挖掘Angular 2的源代码 ,我自己。

As usual, feel free to leave questions in the comments, or shoot them to me on Twitter (@PelekeS); I'll get back to everyone individually.

像往常一样,随时在评论中留下问题,或在Twitter( @PelekeS )上向我射击; 我将单独与每个人联系。

翻译自: https://scotch.io/tutorials/from-javascript-to-typescript-pt-iib-designing-with-classes-interfaces-mixins

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. ROS学习笔记(三)先锋机器人的使用 — 参考 ROS wiki 和 Mobile wiki

    –参考方案&#xff1a; 找到了关于p3-dx的一些关于ROS的资料 https://github.com/ManolisCh/pioneer_p3dx https://github.com/SeRViCE-Lab/p3-dx http://wiki.ros.org/demo_pioneer 先锋机器人ROS的教程&#xff1a; https://www.youtube.com/watch?v-9NHupBPC6Y 首先…...

    2024/4/21 3:26:22
  2. 第七次迭代开发总结(AngularJS下文件上传的实现)

    第七次迭代开发总结 突然之间冒出来一个第七次迭代总结看上去挺奇怪的&#xff0c;事实上因为学校项目的关系&#xff0c;我暑假留校继续开发。在迭代的前半周期&#xff0c;团队进行了一次技术迁移&#xff0c;舍弃LiveScript转向了ECMAScript 6。有空的话会写一些ECMAScript…...

    2024/5/5 18:34:01
  3. “JavaScript Promises和AngularJS $q Service”Part 2 (教程篇)

    欢迎大家到我的博客关注我学习Ionic 1和Ionic 2的历程&#xff0c;共同学习&#xff0c;共同进步。 注&#xff1a;本文是译文&#xff0c;难免有错误或理解不足之处&#xff0c;请大家多多指正&#xff0c;大家也可挪步原文。由于本文讲解十分精彩&#xff0c;非常推荐大家查看…...

    2024/4/28 20:32:58
  4. HEVC相关文档

    转载自 ye_f最终编辑 ye_f虽然也是做编码的&#xff0c;让自己懒得写啊&#xff0c;一下材料源自http://blog.csdn.net/yuanchao99/article/details/6803856&#xff0c;谢谢啊。 •ITU官网&#xff1a; –http://www.itu.int/itu-t/workprog/wp_item.aspx?isn7752•会议文档&…...

    2024/4/21 3:26:19
  5. angularJS关于依赖和模块与amd/cmd的区别,分享下结合使用示例

    angular框架的介绍大家可以参考下官网和中文社区。 下面链接是简介&#xff1a; http://www.angularjs.cn/docs/developer/328.html 简单总结下就是&#xff1a; 双向绑定&#xff0c;可测试性的代码结构&#xff0c;模型视图分离的一个前端MV*框架 其中angular也提供了模型的概…...

    2024/4/21 3:26:18
  6. angularjs完整demo例子

    AngularJS的主要特点是 mvc 数据双向绑定 分模块 依赖注入    mvc m: $Scope 变量 V:视图 c:controllerfunction(){} 控制器 方法    Angularjs的用法 1.在一个有起始标签的元素开始标签内使用 ng-app来指定angularjs的作用范围 2.angularJS的表达式是双大括号 {{}} 里…...

    2024/4/21 3:26:17
  7. x265-1.8版本-x265.h代码注释

    注&#xff1a;问号以及未注释部分 会在x265-1.9版本内更新 /****************************************************************************** Copyright (C) 2013 x265 project** Authors: Steve Borho <steveborho.org>** This program is free software; you can …...

    2024/4/19 22:05:24
  8. angular6学习(九):数据绑定到事件

    实现功能&#xff1a;将html页面中文本框的输入的内容传递到ts文件&#xff0c;然后在html文件中显示ts文件中的这个内容。 html文件 一、绑定到事件 ts文件 显示结果&#xff1a; 二、双向绑定&#xff1a; html: app.module.ts...

    2024/4/20 20:07:11
  9. Angular数据绑定

    Angular的数据绑定分为三种&#xff1a; < h1> {{变量名}} </h1>&#xff1a;插值表达式&#xff08;单向绑定&#xff09;< img [src]"imgUrl"> :属性绑定<button (click)"toPrduct($event)">: 事件绑定($event是一个事件变量) …...

    2024/4/20 20:07:10
  10. Angular10 数据绑定

    Angular10数据绑定 中文官网地址 绑定方式 绑定类型语法分类举例插值、属性、attribute、css类、样式{{expression}}[target] expression’bind-target‘expression’单向从数据源到视图数据绑定{{title}}事件(target)statement’on-target‘statement’单向从视图到数据源的…...

    2024/4/20 20:07:09
  11. Angular如何给动态生成的元素绑定事件

    在AngularJS中&#xff0c;操作DOM一般在指令中完成&#xff0c;事件监听机制是在对于已经静态生成的dom绑定事件&#xff0c;而如果在指令中动态生成了DOM节点&#xff0c;动态生成的节点不会被JS事件监听。 举例来说&#xff1a; angular.module(myapp,[]) .directive(myText…...

    2024/4/21 3:26:16
  12. angular 组件间的双向绑定

    组件间的 双向绑定 child.component.ts ... Component({selector: app-child,template: childname-text:{{childName}}<br/><button (click)reset()>reset</button> })export class ChildComponent{Input() childName:string ;Output() childNameChange …...

    2024/4/21 3:26:15
  13. angular双向绑定—(按钮+下拉)

    checkbox绑定 游戏当中我已阅读勾选 <p><input type"checkbox" [(ngModel)]"sel">阅读并同意条款</p> <p><button [disabled]"!sel">登陆</button></p>export class AppComponent { selfalse;hobby…...

    2024/4/28 19:44:38
  14. angular双向绑定简单实现

    angular双向绑定简单实现 双向绑定原理 声明一个新组件时&#xff0c;将使用代理设计模式来代理每个属性&#xff08;getter和setter&#xff09;。因此&#xff0c;它将能够从代码和用户输入中检测属性值变化代理proxy&#xff1a; Proxy 可以理解成&#xff0c;在目标对象之前…...

    2024/4/29 2:31:09
  15. 【Angular6+】事件绑定

    Angular6 事件绑定 临近毕业开始了第二段实习&#xff0c;因为项目需求&#xff0c;技术栈从Vue转到Angular&#xff0c;才发现Angular已经到7了&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff0c;我两年前还是2来着&#xff0c;看来VAR&#xff08;Vu…...

    2024/4/29 0:10:58
  16. Angular 解除双向绑定(适用Angular2+)

    1 . Angular的双向绑定&#xff0c;一直以来是Angular的一大特点&#xff0c;但凡是有利有弊。有时候需要绑定&#xff0c;有时候就需要解除 2 . 解除方法很简单&#xff0c;就是把数据先转化成JSON,再从JSON解析回来&#xff0c;即可解锁绑定&#xff0c;代码如下&#xff1a…...

    2024/4/28 8:50:44
  17. angular 绑定enter键

    <div class"jumppage" ><input type"text" placeholder"跳转" οnfοcus"this.placeholder" οnblur"this.placeholder跳转" ng-model"current"ng-keyup"goPages($event)"/><div>页&…...

    2024/4/28 8:02:06
  18. Angular 背景图片样式绑定

    // img是图片地址 <div [style.background-image]"url( img )">...

    2024/4/28 0:27:03
  19. angular数值绑定

    前言最近熟悉了angular&#xff0c;写一个小总结啊 叙述理解数据双方相互影响&#xff0c;一方修改另一方也会随之而变化。示例 前言 最近熟悉了angular&#xff0c;写一个小总结啊 叙述 理解 事件绑定 用小括号表示写入响应时间 属性绑定就用中括号表示&#xff0c;调取…...

    2024/4/28 16:03:41
  20. Angular5.0新特性

    文章来自官网部分翻译https://blog.angular.io/version-5-0-0-of-angular-now-available-37e414935ced Angular5.0.0版本已经正式发布1.构建优化 5.0版本默认采用CLI构建和打包。构建优化器是包含在CLI里面的一个工具&#xff0c;通过对你的应用程序更加语义化的理解可以使得你…...

    2024/4/28 16:33:28

最新文章

  1. MCM箱模型实践技术应用与O3形成途径、生成潜势、敏感性分析

    目前&#xff0c;大气臭氧污染成为我国“十四五”期间亟待解决的环境问题。臭氧污染不仅对气候有重要影响&#xff0c;而且对人体健康、植物生长均有严重损害。为了高效、精准地治理区域大气臭氧污染&#xff0c;需要了解臭氧生成的主要途径及其前体物。OBM箱模型可用于模拟光化…...

    2024/5/6 20:31:20
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/6 9:38:23
  3. java的gradle,maven工程中使用selenium

    一、下载selenium库 &#xff08;1&#xff09;gradle工程 工程中会有一个build.gradle.kts的文件&#xff0c;这个文件可以定制 Gradle 的行为 在文件中添加下面代码&#xff0c;然后sync // implementation ("org.seleniumhq.selenium:selenium-java:4.19.1") …...

    2024/5/5 1:15:36
  4. ChatGPT 赚钱初学者指南(上)

    原文&#xff1a;The Beginner’s Guide to Earning Money Online with ChatGPT 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第一章&#xff1a;理解基础知识 什么是 ChatGPT&#xff1f; 在人工智能与人类对话相遇的数字织锦中&#xff0c;ChatGPT 作为一个突出…...

    2024/5/5 8:51:03
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/4 23:54:56
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/4 23:54:56
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/6 9:21:00
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/4 23:55:16
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/4 23:55:06
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/4 23:55:01
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57