React设计模式:深入理解React&Redux原理套路

原文地址

本文从属于笔者的React入门与最佳实践系列,推荐阅读GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean

Communication

React组件一个很大的特性在于其拥有自己完整的生命周期,因此我们可以将React组件视作可自运行的小型系统,它拥有自己的内部状态、输入与输出。

Input

对于React组件而言,其输入的来源就是Props,我们会用如下方式向某个React组件传入数据:


// Title.jsx
class Title extends React.Component {
  render() {
    return 

{ this.props.text }

; } }; Title.propTypes = { text: React.PropTypes.string }; Title.defaultProps = { text: 'Hello world' }; // App.jsx class App extends React.Component { render() { return ; } };</code></pre> <p><code>text</code>是<code>Text</code>组件自己的输入域,父组件<code>App</code>在使用子组件<code>Title</code>时候应该提供<code>text</code>属性值。除了标准的属性名之外,我们还会用到如下两个设置:</p> <ul> <li><p>propTypes:用于定义Props的类型,这有助于追踪运行时误设置的Prop值。</p></li> <li><p>defaultProps:定义Props的默认值,这个在开发时很有帮助</p></li> </ul> <p>Props中还有一个特殊的属性<code>props.children</code>可以允许我们使用子组件:</p> <pre><code> class Title extends React.Component { render() { return ( <h1> { this.props.text } { this.props.children } </h1> ); } }; class App extends React.Component { render() { return ( <Title text='Hello React'> <span>community</span> ); } };

注意,如果我们不主动在Title组件的render函数中设置{this.props.children},那么span标签是不会被渲染出来的。除了Props之外,另一个隐性的组件的输入即是context,整个React组件树会拥有一个context对象,它可以被树中挂载的每个组件所访问到,关于此部分更多的内容请参考依赖注入这一章节。

Output

组件最明显的输出就是渲染后的HTML文本,即是React组件渲染结果的可视化展示。当然,部分包含了逻辑的组件也可能发送或者触发某些Action或者Event。


class Title extends React.Component {
  render() {
    return (
      

); } }; class App extends React.Component { render() { return ; } logoClicked() { console.log('logo clicked'); } };</code></pre> <p>在<code>App</code>组件中我们向<code>Title</code>组件传入了可以从<code>Title</code>调用的回调函数,在<code>logoClicked</code>函数中我们可以设置或者修改需要传回父组件的数据。需要注意的是,React并没有提供可以访问子组件状态的API,换言之,我们不能使用<code>this.props.children[0].state</code>或者类似的方法。正确的从子组件中获取数据的方法应该是在Props中传入回调函数,而这种隔离也有助于我们定义更加清晰的API并且促进了所谓单向数据流。</p> <h1>Composition</h1> <p>React最大的特性之一即是其强大的组件的可组合性,实际上除了React之外,笔者并不知道还有哪个框架能够提供如此简单易用的方式来创建与组合各式各样的组件。本章我们会一起讨论些常用的组合技巧,我们以一个简单的例子来进行讲解。假设在我们的应用中有一个页首栏目,并且其中放置了导航栏。我们创建了三个独立的React组件:<code>App</code>,<code>Header</code>以及<code>Navigation</code>。将这三个组件依次嵌套组合,可以得到以下的代码:</p> <pre><code> <App> <Header> <Navigation> ... </Navigation> </Header> </App></code></pre> <p>而在JSX中组合这些组件的方式就是在需要的时候引用它们:</p> <pre><code> // app.jsx import Header from './Header.jsx'; export default class App extends React.Component { render() { return <Header />; } } // Header.jsx import Navigation from './Navigation.jsx'; export default class Header extends React.Component { render() { return <header><Navigation /></header>; } } // Navigation.jsx export default class Navigation extends React.Component { render() { return (<nav> ... </nav>); } }</code></pre> <p>不过这种方式却可能存在以下的问题:</p> <ul> <li><p>我们将<code>App</code>当做各个组件间的连接线,也是整个应用的入口,因此在<code>App</code>中进行各个独立组件的组合是个不错的方法。不过<code>Header</code>元素中可能包含像图标、搜索栏或者Slogan这样的元素。而如果我们需要另一个不包含<code>Navigation</code>功能的<code>Header</code>组件时,像上面这种直接将<code>Navigation</code>组件硬编码进入<code>Header</code>的方式就会难于修改。</p></li> <li><p>这种硬编码的方式会难以测试,如果我们在<code>Header</code>中加入一些自定义的业务逻辑代码,那么在测试的时候当我们要创建<code>Header</code>实例时,因为其依赖于其他组件而导致了这种依赖层次过深(这里不包含Shallow Rendering这种仅渲染父组件而不渲染嵌套的子组件方式)。</p></li> </ul> <h2>使用React的<code>children</code>API</h2> <p>React为我们提供了<code>this.props.children</code>来允许父组件访问其子组件,这种方式有助于保证我们的<code>Header</code>独立并且不需要与其他组件解耦合。</p> <pre><code> // App.jsx export default class App extends React.Component { render() { return ( <Header> <Navigation /> </Header> ); } } // Header.jsx export default class Header extends React.Component { render() { return <header>{ this.props.children }</header>; } };</code></pre> <p>这种方式也有助于测试,我们可以选择输入空白的<code>div</code>元素,从而将要测试的目标元素隔离开来而专注于我们需要测试的部分。</p> <h2>将子组件以属性方式传入</h2> <p>React组件可以接受Props作为输入,我们也可以选择将需要封装的组件以Props方式传入:</p> <pre><code> // App.jsx class App extends React.Component { render() { var title = <h1>Hello there!</h1>; return ( <Header title={ title }> <Navigation /> </Header> ); } }; // Header.jsx export default class Header extends React.Component { render() { return ( <header> { this.props.title } <hr /> { this.props.children } </header> ); } };</code></pre> <p>这种方式在我们需要对传入的待组合组件进行一些修正时非常适用。</p> <h1>Higher-order components</h1> <p>Higher-Order Components模式看上去非常类似于装饰器模式,它会用于包裹某个组件然后为其添加一些新的功能。这里展示一个简单的用于构造Higher-Order Component的函数:</p> <pre><code> var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} /> ) } }; export default enhanceComponent;</code></pre> <p>通常情况下我们会构建一个工厂函数,接收原始的组件然后返回一个所谓的增强或者包裹后的版本,譬如:</p> <pre><code> var OriginalComponent = () => <p>Hello world.</p>; class App extends React.Component { render() { return React.createElement(enhanceComponent(OriginalComponent)); } };</code></pre> <p>一般来说,高阶组件的首要工作就是渲染原始的组件,我们经常也会将Props与State传递进去,将这两个属性传递进去会有助于我们建立一个数据代理。HOC模式允许我们控制组件的输入,即将需要传入的数据以Props传递进去。譬如我们需要为原始组件添加一些配置:</p> <pre><code> var config = require('path/to/configuration'); var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} title={ config.appTitle } /> ) } };</code></pre> <p>这里对于<code>configuration</code>的细节实现会被隐藏到高阶组件中,原始组件只需要了解从Props中获取到<code>title</code>变量然后渲染到界面上。原始组件并不会关心变量存于何地,从何而来,这种模式最大的优势在于我们能够以独立的模式对该组件进行测试,并且可以非常方便地对该组件进行Mocking。在HOC模式下我们的原始组件会变成这样子:</p> <pre><code> var OriginalComponent = (props) => <p>{ props.title }</p>;</code></pre> <h1>Dependency injection</h1> <p>我们写的大部分组件与模块都会包含一些依赖,合适的依赖管理有助于创建良好可维护的项目结构。而所谓的依赖注入技术正是解决这个问题的常用技巧,无论是在Java还是其他应用程序中,依赖注入都受到了广泛的使用。而React中对于依赖注入的需要也是显而易见的,让我们假设有如下的应用树结构:</p> <pre><code> // Title.jsx export default function Title(props) { return <h1>{ props.title }</h1>; } // Header.jsx import Title from './Title.jsx'; export default function Header() { return ( <header> <Title /> </header> ); } // App.jsx import Header from './Header.jsx'; class App extends React.Component { constructor(props) { super(props); this.state = { title: 'React in patterns' }; } render() { return <Header />; } };</code></pre> <p><code>title</code>这个变量的值是在<code>App</code>组件中被定义好的,我们需要将其传入到<code>Title</code>组件中。最直接的方法就是将其从<code>App</code>组件传入到<code>Header</code>组件,然后再由<code>Header</code>组件传入到<code>Title</code>组件中。这种方法在这里描述的简单的仅有三个组件的应用中还是非常清晰可维护的,不过随着项目功能与复杂度的增加,这种层次化的传值方式会导致很多的组件要去考虑它们并不需要的属性。在上文所讲的HOC模式中我们已经使用了数据注入的方式,这里我们使用同样的技术来注入<code>title</code>变量:</p> <pre><code> // enhance.jsx var title = 'React in patterns'; var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} title={ title } /> ) } }; export default enhanceComponent; // Header.jsx import enhance from './enhance.jsx'; import Title from './Title.jsx'; var EnhancedTitle = enhance(Title); export default function Header() { return ( <header> <EnhancedTitle /> </header> ); }</code></pre> <p>在上文这种HOC模式中,<code>title</code>变量被包含在了一个隐藏的中间层中,我们将其作为Props值传入到原始的<code>Title</code>变量中并且得到一个新的组件。这种方式思想是不错,不过还是只解决了部分问题。现在我们可以不去显式地将<code>title</code>变量传递到<code>Title</code>组件中即可以达到同样的<code>enhance.jsx</code>效果。</p> <p>React为我们提供了<code>context</code>的概念,<code>context</code>是贯穿于整个React组件树允许每个组件访问的对象。有点像所谓的Event Bus,一个简单的例子如下所示:</p> <pre><code> // a place where we'll define the context var context = { title: 'React in patterns' }; class App extends React.Component { getChildContext() { return context; } ... }; App.childContextTypes = { title: React.PropTypes.string }; // a place where we need data class Inject extends React.Component { render() { var title = this.context.title; ... } } Inject.contextTypes = { title: React.PropTypes.string };</code></pre> <p>注意,我们要使用context对象必须要通过<code>childContextTypes</code>与<code>contextTypes</code>指明其构成。如果在<code>context</code>对象中未指明这些那么<code>context</code>会被设置为空,这可能会添加些额外的代码。因此我们最好不要将<code>context</code>当做一个简单的object对象而为其设置一些封装方法:</p> <pre><code> // dependencies.js export default { data: {}, get(key) { return this.data[key]; }, register(key, value) { this.data[key] = value; } }</code></pre> <p>这样,我们的<code>App</code>组件会被改造成这样子:</p> <pre><code> import dependencies from './dependencies'; dependencies.register('title', 'React in patterns'); class App extends React.Component { getChildContext() { return dependencies; } render() { return <Header />; } }; App.childContextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func };</code></pre> <p>而在<code>Title</code>组件中,我们需要进行如下设置:</p> <pre><code> // Title.jsx export default class Title extends React.Component { render() { return <h1>{ this.context.get('title') }</h1> } } Title.contextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func };</code></pre> <p>当然我们不希望在每次要使用<code>contextTypes</code>的时候都需要显式地声明一下,我们可以将这些声明细节包含在一个高阶组件中。</p> <pre><code> // Title.jsx import wire from './wire'; function Title(props) { return <h1>{ props.title }</h1>; } export default wire(Title, ['title'], function resolve(title) { return { title }; });</code></pre> <p>这里的<code>wire</code>函数的第一个参数是React组件对象,第二个参数是一系列需要注入的依赖值,注意,这些依赖值务必已经调用过<code>register</code>函数。最后一个参数则是所谓的映射函数,它接收存储在<code>context</code>中的某个原始值然后返回React Props中需要的值。因为在这个例子里<code>context</code>中存储的值与<code>Title</code>组件中需要的值都是<code>title</code>变量,因此我们直接返回即可。不过在真实的应用中可能是一个数据集合、配置等等。</p> <pre><code> export default function wire(Component, dependencies, mapper) { class Inject extends React.Component { render() { var resolved = dependencies.map(this.context.get.bind(this.context)); var props = mapper(...resolved); return React.createElement(Component, props); } } Inject.contextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func }; return Inject; };</code></pre> <p>这里的Inject就是某个可以访问<code>context</code>的高阶组件,而<code>mapper</code>就是用于接收<code>context</code>中的数据并将其转化为组件所需要的Props的函数。实际上现在大部分的依赖注入的解决方案都是基于<code>context</code>,我觉得了解这种方式的底层原理还是很有意义的。譬如现在流行的<code>Redux</code>,其核心的<code>connect</code>函数与<code>Provider</code>组件都是基于<code>context</code>。</p> <h1>One direction data flow</h1> <p>单向数据流是React中主要的数据驱动模式,其核心概念在于组件并不会修改它们接收到的数据,它们只是负责接收新的数据而后重新渲染到界面上或者发出某些Action以触发某些专门的业务代码来修改数据存储中的数据。我们先设置一个包含一个按钮的<code>Switcher</code>组件,当我们点击该按钮时会触发某个<code>flag</code>变量的改变:</p> <pre><code> class Switcher extends React.Component { constructor(props) { super(props); this.state = { flag: false }; this._onButtonClick = e => this.setState({ flag: !this.state.flag }); } render() { return ( <button onClick={ this._onButtonClick }> { this.state.flag ? 'lights on' : 'lights off' } </button> ); } }; // ... and we render it class App extends React.Component { render() { return <Switcher />; } };</code></pre> <p>此时我们将所有的数据放置到组件内,换言之,<code>Switcher</code>是唯一的包含我们<code>flag</code>变量的地方,我们来尝试下将这些数据托管于专门的Store中:</p> <pre><code> var Store = { _flag: false, set: function(value) { this._flag = value; }, get: function() { return this._flag; } }; class Switcher extends React.Component { constructor(props) { super(props); this.state = { flag: false }; this._onButtonClick = e => { this.setState({ flag: !this.state.flag }, () => { this.props.onChange(this.state.flag); }); } } render() { return ( <button onClick={ this._onButtonClick }> { this.state.flag ? 'lights on' : 'lights off' } </button> ); } }; class App extends React.Component { render() { return <Switcher onChange={ Store.set.bind(Store) } />; } };</code></pre> <p>这里的<code>Store</code>对象是一个简单的单例对象,可以帮助我们设置与获取<code>_flag</code>属性值。而通过将<code>getter</code>函数传递到组件内,可以允许我们在<code>Store</code>外部修改这些变量,此时我们的应用工作流大概是这样的:</p> <pre><code> User's input | Switcher -------> Store</code></pre> <p>假设我们已经将<code>flag</code>值保存到某个后端服务中,我们需要为该组件设置一个合适的初始状态。此时就会存在一个问题在于同一份数据保存在了两个地方,对于UI与<code>Store</code>分别保存了各自独立的关于<code>flag</code>的数据状态,我们等于在<code>Store</code>与<code>Switcher</code>之间建立了双向的数据流:<code>Store ---> Switcher</code>与<code>Switcher ---> Store</code></p> <pre><code> // ... in App component <Switcher value={ Store.get() } onChange={ Store.set.bind(Store) } /> // ... in Switcher component constructor(props) { super(props); this.state = { flag: this.props.value }; ...</code></pre> <p>此时我们的数据流向变成了:</p> <pre><code> User's input | Switcher <-------> Store ^ | | | | | | v Service communicating with our backend</code></pre> <p>在这种双向数据流下,如果我们在外部改变了<code>Store</code>中的状态之后,我们需要将改变之后的最新值更新到<code>Switcher</code>中,这样也在无形之间增加了应用的复杂度。而单向数据流则是解决了这个问题,它强制在全局只保留一个状态存储,通常是存放在Store中。在单向数据流下,我们需要添加一些订阅Store中状态改变的响应函数:</p> <pre><code> var Store = { _handlers: [], _flag: '', onChange: function(handler) { this._handlers.push(handler); }, set: function(value) { this._flag = value; this._handlers.forEach(handler => handler()) }, get: function() { return this._flag; } };</code></pre> <p>然后我们在<code>App</code>组件中设置了钩子函数,这样每次<code>Store</code>改变其值的时候我们都会强制重新渲染:</p> <pre><code> class App extends React.Component { constructor(props) { super(props); Store.onChange(this.forceUpdate.bind(this)); } render() { return ( <div> <Switcher value={ Store.get() } onChange={ Store.set.bind(Store) } /> </div> ); } };</code></pre> <p>注意,这里使用的<code>forceUpdate</code>并不是一个推荐的用法,我们通常会使用HOC模式来进行重渲染,这里使用<code>forceUpdate</code>只是用于演示说明。在基于上述的改造,我们就不需要在组件中继续保留内部状态:</p> <pre><code> class Switcher extends React.Component { constructor(props) { super(props); this._onButtonClick = e => { this.props.onChange(!this.props.value); } } render() { return ( <button onClick={ this._onButtonClick }> { this.props.value ? 'lights on' : 'lights off' } </button> ); } };</code></pre> <p>这种模式的优势在于会将我们的组件改造为简单的<code>Store</code>中数据的呈现,此时才是真正无状态的View。我们可以以完全声明式的方式来编写组件,而将应用中复杂的业务逻辑放置到单独的地方。此时我们应用程序的流图变成了:</p> <pre><code> Service communicating with our backend ^ | v Store <----- | | v | Switcher ----> ^ | | User input</code></pre> <p>在这种单向数据流中我们不再需要同步系统中的多个部分,这种单向数据流的概念并不仅仅适用于基于React的应用。</p> <h1>Flux</h1> <blockquote> <p>关于Flux的简单了解可以参考笔者的GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean</p> </blockquote> <p>Flux是用于构建用户交互界面的架构模式,最早由Facebook在f8大会上提出,自此之后,很多的公司开始尝试这种概念并且貌似这是个很不错的构建前端应用的模式。Flux经常和React一起搭配使用,笔者本身在日常的工作中也是使用React+Flux的搭配,给自己带来了很大的遍历。</p> <p><span class="img-wrap"></span></p> <p>Flux中最主要的角色为Dispatcher,它是整个系统中所有的Events的中转站。Dispatcher负责接收我们称之为Actions的消息通知并且将其转发给所有的Stores。每个Store实例本身来决定是否对该Action感兴趣并且是否相应地改变其内部的状态。当我们将Flux与熟知的MVC相比较,你就会发现Store在某些意义上很类似于Model,二者都是用于存放状态与状态中的改变。而在系统中,除了View层的用户交互可能触发Actions之外,其他的类似于Service层也可能触发Actions,譬如在某个HTTP请求完成之后,请求模块也会发出相应类型的Action来触发Store中对于状态的变更。</p> <p>而在Flux中有个最大的陷阱就是对于数据流的破坏,我们可以在Views中访问Store中的数据,但是我们不应该在Views中修改任何Store的内部状态,所有对于状态的修改都应该通过Actions进行。作者在这里介绍了其维护的某个Flux变种的项目fluxiny。</p> <h2>Dispatcher</h2> <p><span class="img-wrap"></span></p> <p>大部分情况下我们在系统中只需要单个的Dispatcher,它是类似于粘合剂的角色将系统的其他部分有机结合在一起。Dispatcher一般而言有两个输入:Actions与Stores。其中Actions需要被直接转发给Stores,因此我们并不需要记录Actions的对象,而Stores的引用则需要保存在Dispatcher中。基于这个考虑,我们可以编写一个简单的Dispatcher:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { this._stores.push({ store: store }); }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action); }); } } } };</code></pre> <p>在上述实现中我们会发现,每个传入的<code>Store</code>对象都应该拥有一个<code>update</code>方法,因此我们在进行Store的注册时也要来检测该方法是否存在:</p> <pre><code> register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { this._stores.push({ store: store }); } }</code></pre> <p>在完成了对于Store的注册之后,下一步我们就是需要将View与Store关联起来,从而在Store发生改变的时候能够触发View的重渲染:</p> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info8/974ca9e3b62f4161a57891032a210cca.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/974ca9e3b62f4161a57891032a210cca.jpg" alt="React设计模式:深入理解React&Redux原理套路_第1张图片" title="" width="620" height="245" style="border:1px solid black;"></a></span></p> <p>很多flux的实现中都会使用如下的辅助函数:</p> <pre><code> Framework.attachToStore(view, store);</code></pre> <p>不过作者并不是很喜欢这种方式,这样这样会要求View中需要调用某个具体的API,换言之,在View中就需要了解到Store的实现细节,而使得View与Store又陷入了紧耦合的境地。当开发者打算切换到其他的Flux框架时就不得不修改每个View中的相对应的API,那又会增加项目的复杂度。另一种可选的方式就是使用<code>React mixins</code>:</p> <pre><code> var View = React.createClass({ mixins: [Framework.attachToStore(store)] ... });</code></pre> <p>使用<code>mixin</code>是个不错的修改现有的React 组件而不影响其原有代码的方式,不过这种方式的缺陷在于它不能够以一种Predictable的方式去修改组件,用户的可控性较低。还有一种方式就是使用<code>React context</code>,这种方式允许我们将值跨层次地传递给React组件树中的组件而不需要了解它们处于组件树中的哪个层级。这种方式和mixins可能有相同的问题,开发者并不知道该数据从何而来。</p> <p>作者最终选用的方式即是上面提及到的Higher-Order Components模式,它建立了一个包裹函数来对现有组件进行重新打包处理:</p> <pre><code> function attachToStore(Component, store, consumer) { const Wrapper = React.createClass({ getInitialState() { return consumer(this.props, store); }, componentDidMount() { store.onChangeEvent(this._handleStoreChange); }, componentWillUnmount() { store.offChangeEvent(this._handleStoreChange); }, _handleStoreChange() { if (this.isMounted()) { this.setState(consumer(this.props, store)); } }, render() { return <Component {...this.props} {...this.state} />; } }); return Wrapper; };</code></pre> <p>其中<code>Component</code>代指我们需要附着到<code>Store</code>中的View,而<code>consumer</code>则是应该被传递给View的Store中的部分的状态,简单的用法为:</p> <pre><code> class MyView extends React.Component { ... } ProfilePage = connectToStores(MyView, store, (props, store) => ({ data: store.get('key') }));</code></pre> <p>这种模式的优势在于其有效地分割了各个模块间的职责,在该模式中Store并不需要主动地推送消息给View,而主需要简单地修改数据然后广播说我的状态已经更新了,然后由HOC去主动地抓取数据。那么在作者具体的实现中,就是选用了HOC模式:</p> <pre><code> register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer) { consumers.push(consumer); }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } }</code></pre> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info8/572fc31fdbc647e3ba44983263cf5f6d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/572fc31fdbc647e3ba44983263cf5f6d.jpg" alt="React设计模式:深入理解React&Redux原理套路_第2张图片" title="" width="620" height="212" style="border:1px solid black;"></a></span></p> <p>另一个常见的用户场景就是我们需要为界面提供一些默认的状态,换言之当每个<code>consumer</code>注册的时候需要提供一些初始化的默认数据:</p> <pre><code> var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; };</code></pre> <p>综上所述,最终的Dispatcher函数如下所示:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } } } };</code></pre> <h2>Actions</h2> <p>Actions就是在系统中各个模块之间传递的消息载体,作者觉得应该使用标准的Flux Action模式:</p> <pre><code> { type: 'USER_LOGIN_REQUEST', payload: { username: '...', password: '...' } }</code></pre> <p>其中的<code>type</code>属性表明该Action所代表的操作而<code>payload</code>中包含了相关的数据。另外,在某些情况下Action中没有带有Payload,因此可以使用Partial Application方式来创建标准的Action请求:</p> <pre><code> var createAction = function (type) { if (!type) { throw new Error('Please, provide action\'s type.'); } else { return function (payload) { return dispatcher.dispatch({ type: type, payload: payload }); } } }</code></pre> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info8/5cb55e30ad7a4ca3b56ea27d60c7770f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/5cb55e30ad7a4ca3b56ea27d60c7770f.jpg" alt="React设计模式:深入理解React&Redux原理套路_第3张图片" title="" width="620" height="204" style="border:1px solid black;"></a></span></p> <h2>Final Code</h2> <p>上文我们已经了解了核心的Dispatcher与Action的构造过程,那么在这里我们将这二者组合起来:</p> <pre><code> var createSubscriber = function (store) { return dispatcher.register(store); }</code></pre> <p>并且为了不直接暴露dispatcher对象,我们可以允许用户使用<code>createAction</code>与<code>createSubscriber</code>这两个函数:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } } } }; module.exports = { create: function () { var dispatcher = Dispatcher(); return { createAction: function (type) { if (!type) { throw new Error('Please, provide action\'s type.'); } else { return function (payload) { return dispatcher.dispatch({ type: type, payload: payload }); } } }, createSubscriber: function (store) { return dispatcher.register(store); } } } };</code></pre> <p><span class="img-wrap"><img src="http://img.e-com-net.com/image/info8/29df9eb1055a42fe88db86f41996d206.jpg" alt="" title="" width="0" height="0"></span></p> </div> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1305169394015440896"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(React设计模式:深入理解React&Redux原理套路)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1900593147080142848.htm" title="白话设计模式之(53):迭代器模式——数据遍历的“百变魔方”" target="_blank">白话设计模式之(53):迭代器模式——数据遍历的“百变魔方”</a> <span class="text-muted">一杯年华@编程空间</span> <a class="tag" taget="_blank" href="/search/%E7%99%BD%E8%AF%9D%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">白话设计模式</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F/1.htm">迭代器模式</a> <div>白话设计模式之(53):迭代器模式——数据遍历的“百变魔方”大家好!在软件开发的学习过程中,我们都在不断探索如何让代码更加高效、灵活且易于维护。设计模式作为编程领域的关键知识,为我们解决各种复杂问题提供了有力的工具。今天,咱们继续深入研究迭代器模式,它就像一个“百变魔方”,不仅能实现基本的数据遍历功能,还能通过各种扩展和变化,满足不同场景下的数据访问需求。希望通过这篇博客,能和大家一起更全面地理解</div> </li> <li><a href="/article/1900591760128667648.htm" title="深入理解 Java 中 synchronized 的使用和锁升级" target="_blank">深入理解 Java 中 synchronized 的使用和锁升级</a> <span class="text-muted">谢家小布柔</span> <a class="tag" taget="_blank" href="/search/java%E4%B8%AD%E7%9A%84%E9%9D%A2%E8%AF%95%E9%A2%98/1.htm">java中的面试题</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>目录一、synchronized的使用方式(一)修饰普通方法(二)修饰静态方法(三)修饰代码块二、synchronized的锁升级(一)无锁(二)偏向锁(三)轻量级锁(四)重量级锁在Java并发编程中,synchronized是一个非常重要的关键字,用于实现线程同步,保证在同一时刻只有一个线程可以访问被同步的代码块或方法,从而避免多线程带来的数据不一致等问题。同时,Java虚拟机(JVM)为了提高</div> </li> <li><a href="/article/1900591760762007552.htm" title="Java面向对象编程进阶:深入理解static、单例模式与继承" target="_blank">Java面向对象编程进阶:深入理解static、单例模式与继承</a> <span class="text-muted">shy2005_5_31</span> <a class="tag" taget="_blank" href="/search/Java%E5%85%A8%E6%A0%88%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0/1.htm">Java全栈开发学习</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在面向对象编程(OOP)中,掌握高级特性是提升代码质量和设计能力的关键。本文基于Java语言,深入探讨static关键字、单例设计模式、继承等核心概念,并结合实际应用场景与深度思考,帮助读者构建系统化的知识体系。一、static关键字:共享与效率的基石1.静态变量vs实例变量静态变量:用static修饰,属于类,内存中仅一份,被所有对象共享。应用场景:全局计数器、配置参数。publicclassU</div> </li> <li><a href="/article/1900586092499890176.htm" title="React 和 Vue _使用区别" target="_blank">React 和 Vue _使用区别</a> <span class="text-muted">开心小老虎</span> <a class="tag" taget="_blank" href="/search/react%E7%9F%A5%E8%AF%86%E7%82%B9%2B%E7%BB%84%E4%BB%B6/1.htm">react知识点+组件</a><a class="tag" taget="_blank" href="/search/vue3%E7%9F%A5%E8%AF%86%E7%82%B9%2B%E7%BB%84%E4%BB%B6/1.htm">vue3知识点+组件</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%9F%A5%E8%AF%86%E7%82%B9/1.htm">前端知识点</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>目录一、框架介绍1.Vue2.React二、框架结构1.创建应用2.框架结构三、使用区别1.单页面组成2.样式3.显示响应式数据4.响应式html标签属性5.控制元素显隐6.条件渲染7.渲染列表react和vue是目前前端比较流行的两大框架,前端程序员应该将两种框架都掌握,本文总结一些基本知识点的使用区别。一、框架介绍1.VueVue是一个框架,也是一个生态。其功能覆盖了大部分前端开发常见的需求。</div> </li> <li><a href="/article/1900579283978481664.htm" title="DeepSeek面试——分词算法" target="_blank">DeepSeek面试——分词算法</a> <span class="text-muted">mzgong</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>DeepSeek-V3分词算法一、核心算法:字节级BPE(Byte-levelBPE,BBPE)DeepSeek-V3采用字节级BPE(BBPE)作为核心分词算法,这是对传统BPE(BytePairEncoding)算法的改进版本。其核心原理是将文本分解为字节(Byte)序列,通过统计高频相邻字节对的共现频率进行逐层合并,最终形成128K扩展词表。二、BBPE的核心优势1.多语言统一处理能力跨语言</div> </li> <li><a href="/article/1900577268640575488.htm" title="react和vue 基础使用对比" target="_blank">react和vue 基础使用对比</a> <span class="text-muted">圣京都</span> <a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>1.实现功能(ts)0.基础属性使用1.组件直接的通信2.useState动态修改值3.循环遍历功能4.实现类型vue的watch,filter,computed属性功能5.实现类似vue2的生命周期5.类型vuev-if功能的实现2.文件结构图3.具体代码interface.tsimport"./index.less";import{message}from"antd";import{useSt</div> </li> <li><a href="/article/1900572350441648128.htm" title="【Python】全局解释器锁(Global Interpreter Lock,GIL)" target="_blank">【Python】全局解释器锁(Global Interpreter Lock,GIL)</a> <span class="text-muted">彬彬侠</span> <a class="tag" taget="_blank" href="/search/Python%E5%9F%BA%E7%A1%80/1.htm">Python基础</a><a class="tag" taget="_blank" href="/search/%E5%85%A8%E5%B1%80%E8%A7%A3%E9%87%8A%E5%99%A8%E9%94%81/1.htm">全局解释器锁</a><a class="tag" taget="_blank" href="/search/GIL/1.htm">GIL</a><a class="tag" taget="_blank" href="/search/CPython/1.htm">CPython</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E8%BF%9B%E7%A8%8B/1.htm">多进程</a><a class="tag" taget="_blank" href="/search/C/1.htm">C</a><a class="tag" taget="_blank" href="/search/%E6%89%A9%E5%B1%95/1.htm">扩展</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>全局解释器锁(GlobalInterpreterLock,简称GIL)是CPython(Python的标准实现)中的一个机制,它确保同一时刻只有一个线程在执行Python字节码。GIL的主要作用是保护Python内部的数据结构,避免多线程访问共享数据时发生竞争条件,导致数据损坏。GIL的工作原理在Python的多线程环境中,GIL会限制多个线程同时执行Python字节码。尽管操作系统可以调度多个线</div> </li> <li><a href="/article/1900567047360802816.htm" title="Deepseek:物理神经网络PINN入门教程" target="_blank">Deepseek:物理神经网络PINN入门教程</a> <span class="text-muted">天一生水water</span> <a class="tag" taget="_blank" href="/search/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/1.htm">神经网络</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a> <div>一、物理信息网络(PINN)的概念与原理1.定义与来源物理信息网络(Physics-InformedNeuralNetworks,PINN)是一种将物理定律(如偏微分方程、守恒定律等)嵌入神经网络训练过程的深度学习方法。其核心思想是通过神经网络同时拟合观测数据并满足物理约束,从而解决传统数值方法难以处理的高维、噪声数据或复杂边界条件问题。来源:PINN起源于对传统数值方法局限性的改进需求(如网格生</div> </li> <li><a href="/article/1900564399077257216.htm" title="深入理解 Rust 中的模式匹配语法" target="_blank">深入理解 Rust 中的模式匹配语法</a> <span class="text-muted">Hello.Reader</span> <a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>一、匹配字面量在Rust中,可以直接对具体的字面量进行匹配。例如:fnmain(){letx=1;matchx{1=>println!("匹配到字面量1"),_=>println!("其他值"),}}当x的值为1时,匹配成功并打印出对应的信息。对于需要对特定具体值进行处理的场景,这种写法非常直观有效。二、匹配命名变量在模式匹配中,使用命名变量可以将匹配到的值绑定到一个变量上。需要注意的是,在mat</div> </li> <li><a href="/article/1900562371550703616.htm" title="TF-IDF:文本挖掘中的关键词提取利器" target="_blank">TF-IDF:文本挖掘中的关键词提取利器</a> <span class="text-muted">巷955</span> <a class="tag" taget="_blank" href="/search/tf-idf/1.htm">tf-idf</a> <div>引言在自然语言处理(NLP)和文本挖掘中,TF-IDF是一种常用的技术,用于评估一个词在文档中的重要性。它不仅在信息检索领域广泛应用,还在文本分类、关键词提取等任务中发挥着重要作用。本文将详细介绍TF-IDF的原理,并通过一个实际的代码示例来展示如何使用TF-IDF从《红楼梦》中提取核心关键词。1.什么是TF-IDF?TF-IDF是一种统计方法,用于评估一个词在文档中的重要性。它由两部分组成:-T</div> </li> <li><a href="/article/1900561741394276352.htm" title="SEO 优化" target="_blank">SEO 优化</a> <span class="text-muted">前端岳大宝</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A0%B8%E5%BF%83%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/1.htm">前端核心知识总结</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a> <div>以下是SEO(搜索引擎优化)的基础知识点梳理,从前端技术、内容策略到搜索引擎原理,覆盖核心优化方向:一、SEO基础概念定义与目标SEO是通过优化网站结构、内容和技术,提升网站在搜索引擎自然搜索结果中的排名,吸引更多免费流量。核心目标:满足用户搜索意图,同时符合搜索引擎爬虫的抓取规则。搜索引擎工作原理爬取(Crawling):搜索引擎蜘蛛(如Googlebot)抓取网页内容。索引(Indexing)</div> </li> <li><a href="/article/1900558966681825280.htm" title="A800架构设计与实战" target="_blank">A800架构设计与实战</a> <span class="text-muted">智能计算研究中心</span> <a class="tag" taget="_blank" href="/search/%E5%85%B6%E4%BB%96/1.htm">其他</a> <div>内容概要《A800架构设计与实战》围绕新一代计算架构的技术演进与工程落地展开系统性论述。全书以分布式运算优化原理为切入点,通过对核心模块的层级化拆解,深入剖析多节点协同计算中的资源分配、任务调度及通信瓶颈突破方法。为强化理论与实践的结合,书中引入智能制造与云渲染两大典型场景的完整案例,覆盖从需求分析、架构设计到性能调优的全生命周期。技术维度实现路径应用价值架构设计核心模块拆分与重组降低系统耦合度分</div> </li> <li><a href="/article/1900557580397244416.htm" title="echarts实现3d饼图" target="_blank">echarts实现3d饼图</a> <span class="text-muted">qq_45600165</span> <a class="tag" taget="_blank" href="/search/echarts/1.htm">echarts</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>import*asechartsfrom'echarts'import'echarts-gl'//import{ref}from'vue';import{onMounted,onUnmounted,toRefs,ref,reactive,watch}from'vue'exportdefault{props:{//定义prop的名称和类型data:Object},setup(props){letst</div> </li> <li><a href="/article/1900556950790270976.htm" title="MySQL主从复制架构原理及部署(work)" target="_blank">MySQL主从复制架构原理及部署(work)</a> <span class="text-muted">只想按时下班</span> <a class="tag" taget="_blank" href="/search/Mysql/1.htm">Mysql</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/memcached/1.htm">memcached</a> <div>文章目录一、原理1、什么是MySQL主从复制2、MySQL主从复制应用场景3、MySQL主从复制架构及原理4、MySQLbinlog日志三种模式二、主从复制配置搭建1、MySQL8二进制安装2、主从复制配置3、测试主从复制三、二进制日志管理说明四、MySQL主从复制常见问题1、从库binlog落后主库binlog?2、主库update,从库迟迟没有更新3、主从复制延时配置(从库配置)4、主从复制故</div> </li> <li><a href="/article/1900556317920129024.htm" title="python实现KNN算法的手写数字识别:深入解析与完整项目流程" target="_blank">python实现KNN算法的手写数字识别:深入解析与完整项目流程</a> <span class="text-muted">快撑死的鱼</span> <a class="tag" taget="_blank" href="/search/Python%E7%AE%97%E6%B3%95%E7%B2%BE%E8%A7%A3/1.htm">Python算法精解</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>随着人工智能和机器学习的快速发展,图像识别技术在多个领域得到广泛应用。而手写数字识别作为图像识别的典型场景之一,已经成为研究者和开发者学习、应用机器学习算法的经典项目。本文将深入解析如何使用Python编程语言,结合KNN(K-最近邻)算法实现手写数字识别系统。文章不仅介绍了算法的核心原理,还从用户交互、图像处理、数据预处理等多个角度对整个项目进行了全方位的讲解。读者通过本文,可以全面掌握手写数字</div> </li> <li><a href="/article/1900550137126645760.htm" title="密码学:网络安全的基石与未来" target="_blank">密码学:网络安全的基石与未来</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a> <div>在数字化时代,网络安全已成为全球关注的焦点。无论是个人隐私的保护,还是国家关键基础设施的安全,都离不开密码学这一核心技术。密码学不仅是信息安全的基石,更是现代社会中数据保密性、完整性和可用性的守护者。本文将从密码学的基本原理出发,结合最新技术发展,探讨其在网络安全中的核心作用。一、密码学的基本原理密码学的核心目标是通过数学方法保护信息的机密性、完整性和真实性。它主要分为两大领域:对称加密和非对称加</div> </li> <li><a href="/article/1900548876029456384.htm" title="Mysql高频八股——SQL语句的执行过程" target="_blank">Mysql高频八股——SQL语句的执行过程</a> <span class="text-muted">钢板兽</span> <a class="tag" taget="_blank" href="/search/%E9%AB%98%E9%A2%91%E5%85%AB%E8%82%A1/1.htm">高频八股</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>大家好,我是钢板兽!今天这篇文章本来想把SQL语句的执行过程和事务与undolog、redolog的联系放在一起写的。SQL语句的执行过程中会涉及到undolog、redolog,而undolog、redolog更深入的原理也是面试中经常会问到的,所以把它们放在一起再合适不过了,但是写着写着发现内容太多,于是拆成了两篇。这篇文章会带你理解SQL语句的执行过程,在探究SQL语句的执行过程前,我们要先</div> </li> <li><a href="/article/1900547235578441728.htm" title="从零到一:Transformer模型的原理与实战之旅" target="_blank">从零到一:Transformer模型的原理与实战之旅</a> <span class="text-muted">樽酒ﻬق</span> <a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/transformer/1.htm">transformer</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>目录从零到一:Transformer模型的原理与实战之旅1.Transformer原理简介1.1什么是Transformer?1.2自注意力机制的核心1.3Transformer的结构2.实战:构建Transformer模型2.1任务目标2.2环境准备2.3数据准备2.4模型构建2.5模型训练3.推理实战:完整示例与输出结果3.1完整推理代码3.2代码解析4.原理与代码的结合4.1自注意力机制的实</div> </li> <li><a href="/article/1900544964740313088.htm" title="Unity AI 技术浅析(三):智能代理(Agents)" target="_blank">Unity AI 技术浅析(三):智能代理(Agents)</a> <span class="text-muted">爱研究的小牛</span> <a class="tag" taget="_blank" href="/search/AIGC%E2%80%94%E8%99%9A%E6%8B%9F%E7%8E%B0%E5%AE%9E/1.htm">AIGC—虚拟现实</a><a class="tag" taget="_blank" href="/search/AIGC%E2%80%94%E6%B8%B8%E6%88%8F%E5%88%B6%E4%BD%9C/1.htm">AIGC—游戏制作</a><a class="tag" taget="_blank" href="/search/unity/1.htm">unity</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%88%8F%E5%BC%95%E6%93%8E/1.htm">游戏引擎</a><a class="tag" taget="_blank" href="/search/AIGC/1.htm">AIGC</a> <div>UnityAI的智能代理(Agents)技术是实现游戏和虚拟现实应用中非玩家角色(NPC)、敌人、盟友等智能行为的核心。通过智能代理,开发者可以为虚拟角色赋予感知、决策和行动的能力,使其能够与环境和其他角色进行复杂的交互。一、智能代理的基本原理智能代理是能够在特定环境中感知、决策和行动的计算实体。在Unity中,智能代理通常用于模拟游戏中的NPC、敌人、盟友等角色。其基本原理包括以下几个方面:1.</div> </li> <li><a href="/article/1900542567678799872.htm" title="为什么程序员需要学习数字电路" target="_blank">为什么程序员需要学习数字电路</a> <span class="text-muted">Vitalia</span> <a class="tag" taget="_blank" href="/search/%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80/1.htm">理论基础</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/1.htm">程序人生</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E5%AD%97%E7%94%B5%E8%B7%AF/1.htm">数字电路</a> <div>在编程的世界里,我们通常关注的是算法、数据结构、框架和设计模式等软件层面的知识。然而,数字电路作为计算机硬件的核心基础,对程序员来说同样重要。掌握数字电路不仅能帮助我们更好地理解计算机的底层原理,还能在实际开发中解决一些棘手的问题。本文将通过理论和实例,探讨程序员学习数字电路的必要性。1.数字电路与计算机的关系计算机的核心是中央处理器(CPU),而CPU的本质是由大量的数字电路组成的。数字电路通过</div> </li> <li><a href="/article/1900539035621847040.htm" title="Oracle RAC 三种心跳机制" target="_blank">Oracle RAC 三种心跳机制</a> <span class="text-muted">数据库急诊日记</span> <a class="tag" taget="_blank" href="/search/%E6%95%85%E9%9A%9C%E5%A4%84%E7%90%86/1.htm">故障处理</a><a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/database/1.htm">database</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a> <div>在OracleRAC(RealApplicationClusters)中,心跳(Heartbeat)是集群节点间用于检测存活状态的核心机制,确保节点间的通信正常并避免脑裂(SplitBrain)问题。以下是RAC的三种关键心跳机制及其作用:1.网络心跳(NetworkHeartbeat)作用:通过私有网络互联(PrivateInterconnect)实时检测节点间的通信状态。工作原理:每个节点周期</div> </li> <li><a href="/article/1900537395221164032.htm" title="数据分析及人工智能框架汇总" target="_blank">数据分析及人工智能框架汇总</a> <span class="text-muted">xihuanyuye</span> <a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a> <div>一、数据分析二、人工智能1、Tensorflow1、简介TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流图的一端流动到另一端计算过程。TensorFlow是将复杂的数据结构传输至人工智能神经网中进行分析和处理过程的系统。Tenso</div> </li> <li><a href="/article/1900534495820443648.htm" title="热修复框架Tinker与Robust原理剖析" target="_blank">热修复框架Tinker与Robust原理剖析</a> <span class="text-muted">Ya-Jun</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>热修复框架Tinker与Robust原理剖析一、热修复技术概述1.1什么是热修复热修复(HotFix)是Android平台上的一种动态修复机制,它允许应用在不重新发布版本的情况下,动态修复线上bug。这种技术对于快速修复线上问题、降低用户流失率具有重要意义。1.2热修复的应用场景紧急bug修复功能动态更新A/B测试动态功能控制1.3主流热修复方案对比方案优点缺点适用场景Tinker支持全量更新、性</div> </li> <li><a href="/article/1900531973835780096.htm" title="谈为什么KLA和Camtech公司为什么可以做到,半导体那边,晶圆,键合可以做到不管哪款新产品进来。编程2小时,上线后准确率可以直接做到99.9%、" target="_blank">谈为什么KLA和Camtech公司为什么可以做到,半导体那边,晶圆,键合可以做到不管哪款新产品进来。编程2小时,上线后准确率可以直接做到99.9%、</a> <span class="text-muted">*Major*</span> <a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/1.htm">机器视觉</a> <div>谈为什么KLA和Camtech公司为什么可以做到,半导体那边,晶圆,键合可以做到不管哪款新产品进来。编程2小时,上线后准确率可以直接做到99.9%、这么里面的AI原理没什么,还是这些公司把AI技术层面用出花了,一是他们有公司可能比较成立时间长,数据丰富。二是像AI深度学习网络冻结,或者自适应调参,都是一些AI技巧,他们用的比较好。三什么跨层特征解耦,实现的基础是他们对半导体理解比较深刻KLA和Ca</div> </li> <li><a href="/article/1900531088057495552.htm" title="【QT教程】QT6硬件数据库编程 QT硬件数据库" target="_blank">【QT教程】QT6硬件数据库编程 QT硬件数据库</a> <span class="text-muted">QT性能优化QT原理源码QT界面美化</span> <a class="tag" taget="_blank" href="/search/qt/1.htm">qt</a><a class="tag" taget="_blank" href="/search/qt6.3/1.htm">qt6.3</a><a class="tag" taget="_blank" href="/search/qt5/1.htm">qt5</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/QT%E6%95%99%E7%A8%8B/1.htm">QT教程</a> <div>QT6硬件数据库编程使用AI技术辅助生成QT界面美化视频课程QT性能优化视频课程QT原理与源码分析视频课程QTQMLC++扩展开发视频课程免费QT视频课程您可以看免费1000+个QT技术视频免费QT视频课程QT统计图和QT数据可视化视频免费看免费QT视频课程QT性能优化视频免费看免费QT视频课程QT界面美化视频免费看1QT6硬件数据库编程基础1.1QT6数据库引擎概述1.1.1QT6数据库引擎概述</div> </li> <li><a href="/article/1900519861356916736.htm" title="MyBatis底层原理深度解析:动态代理与注解如何实现ORM映射" target="_blank">MyBatis底层原理深度解析:动态代理与注解如何实现ORM映射</a> <span class="text-muted">rider189</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a> <div>一、引言MyBatis作为一款优秀的ORM框架,其核心设计思想是通过动态代理和注解将接口方法与SQL操作解耦。开发者只需定义Mapper接口并添加注解,便能实现数据库操作,这背后隐藏着精妙的动态代理机制与源码设计。本文将从源码层解析MyBatis如何实现这一过程。二、动态代理机制:从接口到实现类关键点:MyBatis通过JDK动态代理为Mapper接口生成代理对象,拦截所有方法调用,将其路由到SQ</div> </li> <li><a href="/article/1900518092304347136.htm" title="设计模式学习手册(四)(原型模式)" target="_blank">设计模式学习手册(四)(原型模式)</a> <span class="text-muted">勇敢一点♂</span> <a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/1.htm">原型模式</a> <div>写在前面书接上文设计模式学习手册(三)(建造者模式)原型模式简单来说就是复制一个已存在的原型实例,并对其进行必要的修改,来创建新的对象。原型模式通常会有一个clone()方法用于复制对象。优点:直接复制现有对象,避免了重复的初始化过程,减少开销。可以动态地改变克隆对象的属性,适应不同的需求。无需关心对象的构造细节,通过复制现有实例即可创建新对象。缺点:会涉及到编程中的一个经典问题:深浅拷贝Clon</div> </li> <li><a href="/article/1900515821621407744.htm" title="嵌入式人工智能应用- 第七章 人脸识别" target="_blank">嵌入式人工智能应用- 第七章 人脸识别</a> <span class="text-muted">数贾电子科技</span> <a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%BA%94%E7%94%A8/1.htm">嵌入式人工智能应用</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>嵌入式人工智能应用`文章目录嵌入式人工智能应用1人脸识别1.1dlib介绍1.2dlib特点1.3dlib的安装与编译2人脸识别原理2.1ResNet3代码部署3.1安装[CUDAToolkit12.8](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubunt</div> </li> <li><a href="/article/1900510523351429120.htm" title="使用DeepSeek完成一个简单嵌入式开发" target="_blank">使用DeepSeek完成一个简单嵌入式开发</a> <span class="text-muted">大牛攻城狮</span> <a class="tag" taget="_blank" href="/search/AI%E8%83%BD%E6%9B%BF%E6%8D%A2%E7%A0%81%E5%86%9C/1.htm">AI能替换码农</a><a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a><a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a><a class="tag" taget="_blank" href="/search/AI%E6%9B%BF%E4%BB%A3%E7%A0%81%E5%86%9C/1.htm">AI替代码农</a><a class="tag" taget="_blank" href="/search/STM32/1.htm">STM32</a><a class="tag" taget="_blank" href="/search/%E6%B5%81%E6%B0%B4%E7%81%AF/1.htm">流水灯</a> <div>开启DeepSeek对话请帮我使用AltiumDesigner设计原理图、PCB,使用keil完成代码编写;要求:使用stm32F103RCT6为主控芯片,控制3个流水灯的原理图这里需要注意,每次DeepSeek的回答都不太一样。DeepSeek回答以下是使用STM32F103RCT6控制3个流水灯的完整设计流程,分为硬件设计和软件开发两部分:一、硬件设计(AltiumDesigner)1.原理图</div> </li> <li><a href="/article/1900510145260089344.htm" title="LeetCode:93. 复原 IP 地址(DFS Java)" target="_blank">LeetCode:93. 复原 IP 地址(DFS Java)</a> <span class="text-muted">Cosmoshhhyyy</span> <a class="tag" taget="_blank" href="/search/LeetCode/1.htm">LeetCode</a><a class="tag" taget="_blank" href="/search/leetcode/1.htm">leetcode</a><a class="tag" taget="_blank" href="/search/tcp%2Fip/1.htm">tcp/ip</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88/1.htm">深度优先</a> <div>目录93.复原IP地址题目描述:实现代码与解析:DFS原理思路:93.复原IP地址题目描述:有效IP地址正好由四个整数(每个整数位于0到255之间组成,且不能含有前导0),整数之间用'.'分隔。例如:"0.1.2.201"和"192.168.1.1"是有效IP地址,但是"0.011.255.245"、"192.168.1.312"和"192.168@1.1"是无效IP地址。给定一个只包含数字的字符</div> </li> <li><a href="/article/34.htm" title="Java 并发包之线程池和原子计数" target="_blank">Java 并发包之线程池和原子计数</a> <span class="text-muted">lijingyao8206</span> <a class="tag" taget="_blank" href="/search/Java%E8%AE%A1%E6%95%B0/1.htm">Java计数</a><a class="tag" taget="_blank" href="/search/ThreadPool/1.htm">ThreadPool</a><a class="tag" taget="_blank" href="/search/%E5%B9%B6%E5%8F%91%E5%8C%85/1.htm">并发包</a><a class="tag" taget="_blank" href="/search/java%E7%BA%BF%E7%A8%8B%E6%B1%A0/1.htm">java线程池</a> <div>对于大数据量关联的业务处理逻辑,比较直接的想法就是用JDK提供的并发包去解决多线程情况下的业务数据处理。线程池可以提供很好的管理线程的方式,并且可以提高线程利用率,并发包中的原子计数在多线程的情况下可以让我们避免去写一些同步代码。     这里就先把jdk并发包中的线程池处理器ThreadPoolExecutor 以原子计数类AomicInteger 和倒数计时锁C</div> </li> <li><a href="/article/161.htm" title="java编程思想 抽象类和接口" target="_blank">java编程思想 抽象类和接口</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%8A%BD%E8%B1%A1%E7%B1%BB/1.htm">抽象类</a><a class="tag" taget="_blank" href="/search/%E6%8E%A5%E5%8F%A3/1.htm">接口</a> <div>接口c++对接口和内部类只有简介的支持,但在java中有队这些类的直接支持   1 ,抽象类 :  如果一个类包含一个或多个抽象方法,该类必须限定为抽象类(否者编译器报错)   抽象方法 : 在方法中仅有声明而没有方法体    package com.wj.Interface; </div> </li> <li><a href="/article/288.htm" title="[房地产与大数据]房地产数据挖掘系统" target="_blank">[房地产与大数据]房地产数据挖掘系统</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a> <div>        随着一个关键核心技术的突破,我们已经是独立自主的开发某些先进模块,但是要完全实现,还需要一定的时间...        所以,除了代码工作以外,我们还需要关心一下非技术领域的事件..比如说房地产     &nb</div> </li> <li><a href="/article/415.htm" title="数组队列总结" target="_blank">数组队列总结</a> <span class="text-muted">沐刃青蛟</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E7%BB%84%E9%98%9F%E5%88%97/1.htm">数组队列</a> <div>      数组队列是一种大小可以改变,类型没有定死的类似数组的工具。不过与数组相比,它更具有灵活性。因为它不但不用担心越界问题,而且因为泛型(类似c++中模板的东西)的存在而支持各种类型。      以下是数组队列的功能实现代码:   import List.Student; public class</div> </li> <li><a href="/article/542.htm" title="Oracle存储过程无法编译的解决方法" target="_blank">Oracle存储过程无法编译的解决方法</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B%E3%80%80/1.htm">存储过程 </a> <div>今天同事修改Oracle存储过程又导致2个过程无法被编译,流程规范上的东西,Dave 这里不多说,看看怎么解决问题。   1.     查看无效对象 XEZF@xezf(qs-xezf-db1)> select object_name,object_type,status from all_objects where status='IN</div> </li> <li><a href="/article/669.htm" title="重装系统之后oracle恢复" target="_blank">重装系统之后oracle恢复</a> <span class="text-muted">文强chu</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a> <div>前几天正在使用电脑,没有暂停oracle的各种服务。 突然win8.1系统奔溃,无法修复,开机时系统 提示正在搜集错误信息,然后再开机,再提示的无限循环中。 无耐我拿出系统u盘 准备重装系统,没想到竟然无法从u盘引导成功。 晚上到外面早了一家修电脑店,让人家给装了个系统,并且那哥们在我没反应过来的时候, 直接把我的c盘给格式化了 并且清理了注册表,再装系统。 然后的结果就是我的oracl</div> </li> <li><a href="/article/796.htm" title="python学习二( 一些基础语法)" target="_blank">python学习二( 一些基础语法)</a> <span class="text-muted">小桔子</span> <a class="tag" taget="_blank" href="/search/pthon/1.htm">pthon</a><a class="tag" taget="_blank" href="/search/%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95/1.htm">基础语法</a> <div>紧接着把!昨天没看继续看django 官方教程,学了下python的基本语法 与c类语言还是有些小差别: 1.ptyhon的源文件以UTF-8编码格式 2. /   除 结果浮点型 //  除 结果整形 %   除 取余数 *   乘 **  乘方 eg 5**2 结果是5的2次方25 _&</div> </li> <li><a href="/article/923.htm" title="svn 常用命令" target="_blank">svn 常用命令</a> <span class="text-muted">aichenglong</span> <a class="tag" taget="_blank" href="/search/SVN/1.htm">SVN</a><a class="tag" taget="_blank" href="/search/%E7%89%88%E6%9C%AC%E5%9B%9E%E9%80%80/1.htm">版本回退</a> <div>1 svn回退版本   1)在window中选择log,根据想要回退的内容,选择revert this version或revert chanages from this version 两者的区别:   revert this version:表示回退到当前版本(该版本后的版本全部作废)   revert chanages from this versio</div> </li> <li><a href="/article/1050.htm" title="某小公司面试归来" target="_blank">某小公司面试归来</a> <span class="text-muted">alafqq</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>先填单子,还要写笔试题,我以时间为急,拒绝了它。。时间宝贵。 老拿这些对付毕业生的东东来吓唬我。。 面试官很刁难,问了几个问题,记录下; 1,包的范围。。。public,private,protect. --悲剧了 2,hashcode方法和equals方法的区别。谁覆盖谁.结果,他说我说反了。 3,最恶心的一道题,抽象类继承抽象类吗?(察,一般它都是被继承的啊) 4,stru</div> </li> <li><a href="/article/1177.htm" title="动态数组的存储速度比较 集合框架" target="_blank">动态数组的存储速度比较 集合框架</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6/1.htm">集合框架</a> <div>集合框架: 自定义数据结构(增删改查等) package 数组; /** * 创建动态数组 * @author 百合 * */ public class ArrayDemo{ //定义一个数组来存放数据 String[] src = new String[0]; /** * 增加元素加入容器 * @param s要加入容器</div> </li> <li><a href="/article/1304.htm" title="用JS实现一个JS对象,对象里有两个属性一个方法" target="_blank">用JS实现一个JS对象,对象里有两个属性一个方法</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/js%E5%AF%B9%E8%B1%A1/1.htm">js对象</a> <div><html> <head> </head> <body> 用js代码实现一个js对象,对象里有两个属性,一个方法 </body> <script> var obj={a:'1234567',b:'bbbbbbbbbb',c:function(x){ </div> </li> <li><a href="/article/1431.htm" title="探索JUnit4扩展:使用Rule" target="_blank">探索JUnit4扩展:使用Rule</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a><a class="tag" taget="_blank" href="/search/JUnit/1.htm">JUnit</a><a class="tag" taget="_blank" href="/search/Rule/1.htm">Rule</a> <div>        在上一篇文章中,讨论了使用Runner扩展JUnit4的方式,即直接修改Test Runner的实现(BlockJUnit4ClassRunner)。但这种方法显然不便于灵活地添加或删除扩展功能。下面将使用JUnit4.7才开始引入的扩展方式——Rule来实现相同的扩展功能。 1. Rule       &n</div> </li> <li><a href="/article/1558.htm" title="[Gson一]非泛型POJO对象的反序列化" target="_blank">[Gson一]非泛型POJO对象的反序列化</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/POJO/1.htm">POJO</a> <div>当要将JSON数据串反序列化自身为非泛型的POJO时,使用Gson.fromJson(String, Class)方法。自身为非泛型的POJO的包括两种: 1. POJO对象不包含任何泛型的字段 2. POJO对象包含泛型字段,例如泛型集合或者泛型类 Data类 a.不是泛型类, b.Data中的集合List和Map都是泛型的 c.Data中不包含其它的POJO    </div> </li> <li><a href="/article/1685.htm" title="【Kakfa五】Kafka Producer和Consumer基本使用" target="_blank">【Kakfa五】Kafka Producer和Consumer基本使用</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>0.Kafka服务器的配置 一个Broker, 一个Topic Topic中只有一个Partition()   1. Producer: package kafka.examples.producers; import kafka.producer.KeyedMessage; import kafka.javaapi.producer.Producer; impor</div> </li> <li><a href="/article/1812.htm" title="lsyncd实时同步搭建指南——取代rsync+inotify" target="_blank">lsyncd实时同步搭建指南——取代rsync+inotify</a> <span class="text-muted">ronin47</span> <div>1. 几大实时同步工具比较 1.1 inotify + rsync 最近一直在寻求生产服务服务器上的同步替代方案,原先使用的是 inotify + rsync,但随着文件数量的增大到100W+,目录下的文件列表就达20M,在网络状况不佳或者限速的情况下,变更的文件可能10来个才几M,却因此要发送的文件列表就达20M,严重减低的带宽的使用效率以及同步效率;更为要紧的是,加入inotify</div> </li> <li><a href="/article/1939.htm" title="java-9. 判断整数序列是不是二元查找树的后序遍历结果" target="_blank">java-9. 判断整数序列是不是二元查找树的后序遍历结果</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> public class IsBinTreePostTraverse{ static boolean isBSTPostOrder(int[] a){ if(a==null){ return false; } /*1.只有一个结点时,肯定是查找树 *2.只有两个结点时,肯定是查找树。例如{5,6}对应的BST是 6 {6,5}对应的BST是</div> </li> <li><a href="/article/2066.htm" title="MySQL的sum函数返回的类型" target="_blank">MySQL的sum函数返回的类型</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/jdbc/1.htm">jdbc</a> <div>今天项目切换数据库时,出错 访问数据库的代码大概是这样: String sql = "select sum(number) as sumNumberOfOneDay from tableName"; List<Map> rows = getJdbcTemplate().queryForList(sql); for (Map row : rows</div> </li> <li><a href="/article/2193.htm" title="java设计模式之单例模式" target="_blank">java设计模式之单例模式</a> <span class="text-muted">chicony</span> <a class="tag" taget="_blank" href="/search/java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">java设计模式</a> <div> 在阎宏博士的《JAVA与模式》一书中开头是这样描述单例模式的:   作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 单例模式的结构   单例模式的特点: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。   饿汉式单例类   publ</div> </li> <li><a href="/article/2320.htm" title="javascript取当月最后一天" target="_blank">javascript取当月最后一天</a> <span class="text-muted">ctrain</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div> <!--javascript取当月最后一天--> <script language=javascript> var current = new Date(); var year = current.getYear(); var month = current.getMonth(); showMonthLastDay(year, mont</div> </li> <li><a href="/article/2447.htm" title="linux tune2fs命令详解" target="_blank">linux tune2fs命令详解</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/tune2fs/1.htm">tune2fs</a><a class="tag" taget="_blank" href="/search/%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E6%96%87%E4%BB%B6%E5%9D%97%E4%BF%A1%E6%81%AF/1.htm">查看系统文件块信息</a> <div>一.简介: tune2fs是调整和查看ext2/ext3文件系统的文件系统参数,Windows下面如果出现意外断电死机情况,下次开机一般都会出现系统自检。Linux系统下面也有文件系统自检,而且是可以通过tune2fs命令,自行定义自检周期及方式。 二.用法: Usage: tune2fs [-c max_mounts_count] [-e errors_behavior] [-g grou</div> </li> <li><a href="/article/2574.htm" title="做有中国特色的程序员" target="_blank">做有中国特色的程序员</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a> <div>  从出版业说起 网络作品排到靠前的,都不会太难看,一般人不爱看某部作品也是因为不喜欢这个类型,而此人也不会全不喜欢这些网络作品。究其原因,是因为网络作品都是让人先白看的,看的好了才出了头。而纸质作品就不一定了,排行榜靠前的,有好作品,也有垃圾。 许多大牛都是写了博客,后来出了书。这些书也都不次,可能有人让为不好,是因为技术书不像小说,小说在读故事,技术书是在学知识或温习知识,有</div> </li> <li><a href="/article/2701.htm" title="Android:TextView属性大全" target="_blank">Android:TextView属性大全</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/textview/1.htm">textview</a> <div>android:autoLink    设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web/email/phone/map/all)  android:autoText    如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输</div> </li> <li><a href="/article/2828.htm" title="tomcat虚拟目录安装及其配置" target="_blank">tomcat虚拟目录安装及其配置</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/tomcat%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E/1.htm">tomcat配置说明</a><a class="tag" taget="_blank" href="/search/tomca%E9%83%A8%E7%BD%B2web%E5%BA%94%E7%94%A8/1.htm">tomca部署web应用</a><a class="tag" taget="_blank" href="/search/tomcat%E8%99%9A%E6%8B%9F%E7%9B%AE%E5%BD%95%E5%AE%89%E8%A3%85/1.htm">tomcat虚拟目录安装</a> <div>转载请出自出处:http://eksliang.iteye.com/blog/2097184 1.-------------------------------------------tomcat  目录结构 config:存放tomcat的配置文件 temp  :存放tomcat跑起来后存放临时文件用的 work   : 当第一次访问应用中的jsp</div> </li> <li><a href="/article/2955.htm" title="浅谈:APP有哪些常被黑客利用的安全漏洞" target="_blank">浅谈:APP有哪些常被黑客利用的安全漏洞</a> <span class="text-muted">gg163</span> <a class="tag" taget="_blank" href="/search/APP/1.htm">APP</a> <div>首先,说到APP的安全漏洞,身为程序猿的大家应该不陌生;如果抛开安卓自身开源的问题的话,其主要产生的原因就是开发过程中疏忽或者代码不严谨引起的。但这些责任也不能怪在程序猿头上,有时会因为BOSS时间催得紧等很多可观原因。由国内移动应用安全检测团队爱内测(ineice.com)的CTO给我们浅谈关于Android 系统的开源设计以及生态环境。 1. 应用反编译漏洞:APK 包非常容易被反编译成可读</div> </li> <li><a href="/article/3082.htm" title="C#根据网址生成静态页面" target="_blank">C#根据网址生成静态页面</a> <span class="text-muted">hvt</span> <a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/hovertree/1.htm">hovertree</a> <div>HoverTree开源项目中HoverTreeWeb.HVTPanel的Index.aspx文件是后台管理的首页。包含生成留言板首页,以及显示用户名,退出等功能。根据网址生成页面的方法:   bool CreateHtmlFile(string url, string path) { //http://keleyi.com/a/bjae/3d10wfax.htm stri</div> </li> <li><a href="/article/3209.htm" title="SVG 教程 (一)" target="_blank">SVG 教程 (一)</a> <span class="text-muted">天梯梦</span> <a class="tag" taget="_blank" href="/search/svg/1.htm">svg</a> <div>SVG 简介 SVG 是使用 XML 来描述二维图形和绘图程序的语言。 学习之前应具备的基础知识: 继续学习之前,你应该对以下内容有基本的了解: HTML XML 基础 如果希望首先学习这些内容,请在本站的首页选择相应的教程。 什么是SVG? SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用来定义用于网络的基于矢量</div> </li> <li><a href="/article/3336.htm" title="一个简单的java栈" target="_blank">一个简单的java栈</a> <span class="text-muted">luyulong</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E6%A0%88/1.htm">栈</a> <div> public class MyStack { private long[] arr; private int top; public MyStack() { arr = new long[10]; top = -1; } public MyStack(int maxsize) { arr = new long[maxsize]; top </div> </li> <li><a href="/article/3463.htm" title="基础数据结构和算法八:Binary search" target="_blank">基础数据结构和算法八:Binary search</a> <span class="text-muted">sunwinner</span> <a class="tag" taget="_blank" href="/search/Algorithm/1.htm">Algorithm</a><a class="tag" taget="_blank" href="/search/Binary+search/1.htm">Binary search</a> <div>Binary search needs an ordered array so that it can use array indexing to dramatically reduce the number of compares required for each search, using the classic and venerable binary search algori</div> </li> <li><a href="/article/3590.htm" title="12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!" target="_blank">12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!</a> <span class="text-muted">刘星宇</span> <a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个! 1.gets()函数 问:请找出下面代码里的问题: #include<stdio.h> int main(void) {     char buff[10];     memset(buff,0,sizeof(buff)); </div> </li> <li><a href="/article/3717.htm" title="ITeye 7月技术图书有奖试读获奖名单公布" target="_blank">ITeye 7月技术图书有奖试读获奖名单公布</a> <span class="text-muted">ITeye管理员</span> <a class="tag" taget="_blank" href="/search/%E6%B4%BB%E5%8A%A8/1.htm">活动</a><a class="tag" taget="_blank" href="/search/ITeye/1.htm">ITeye</a><a class="tag" taget="_blank" href="/search/%E8%AF%95%E8%AF%BB/1.htm">试读</a> <div>ITeye携手人民邮电出版社图灵教育共同举办的7月技术图书有奖试读活动已圆满结束,非常感谢广大用户对本次活动的关注与参与。 7月试读活动回顾: http://webmaster.iteye.com/blog/2092746 本次技术图书试读活动的优秀奖获奖名单及相应作品如下(优秀文章有很多,但名额有限,没获奖并不代表不优秀): 《Java性能优化权威指南》 </div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>