Placeholder Image

字幕列表 影片播放

由 AI 自動生成
  • Keeping your code clean and tested are the two most important development practices.

    保持代碼整潔和經過測試是兩個最重要的開發實踐。

  • In Flutter, this is even more true than with other frameworks, because on one hand, it's nice to hack a quick app together, on the other hand, larger projects start falling apart when you mix the business logic everywhere, which is so simple to do with Flutter, because even the UI is written in the same programming language in which you write the actual logic.

    在 Flutter 中,這一點甚至比其他框架更真實,因為一方面,快速創建一個應用程序是件好事,另一方面,當你把業務邏輯混在一起時,大型項目就會開始分崩離析,而在 Flutter 中做到這一點非常簡單,因為甚至用戶界面也是用編寫實際邏輯的編程語言編寫的。

  • Even state patterns like block are not sufficient in themselves to allow for easily extensible codebase, and this is where we can employ clean architecture and test-driven development.

    即使是像塊這樣的狀態模式,其本身也不足以讓代碼庫易於擴展,這就是我們可以採用簡潔架構和測試驅動開發的地方。

  • As proposed by our friendly Uncle Bob, Robert Cecil Martin, we should all strive to separate our code into independent layers, and that's precisely what you are going to learn how to do in Flutter in this course.

    正如我們友好的鮑勃叔叔羅伯特-塞西爾-馬丁(Robert Cecil Martin)所建議的,我們都應該努力將代碼分離成獨立的層,而這正是您在本課程中將學習如何在 Flutter 中做到的。

  • Hello, welcome to ResoCoder, where you are getting prepared for real app development by building better, faster, more stable apps.

    您好,歡迎來到 ResoCoder,在這裡,您將通過構建更好、更快、更穩定的應用程序,為真正的應用程序開發做好準備。

  • So subscribe and hit the bell if you want to grow your coding skills and learn about clean architecture in Flutter.

    如果你想提高編碼技能並學習 Flutter 中的簡潔架構,請訂閱並按鈴。

  • Let's start off with the completely finished app, which you will have built by the end of this is actually a numbers API, which provides some nice trivia about numbers.

    讓我們從完全完成的應用程序開始吧,到最後你將會創建一個數字應用程序接口,它提供了一些有關數字的小知識。

  • So we can input a number here, for example, 1, 2, 3, and then search for the trivia.

    是以,我們可以在這裡輸入一個數字,例如 1、2、3,然後搜索瑣事。

  • Let's search for yet another number, for example, 42, right?

    我們再搜索一個數字,比如 42,對嗎?

  • And we can also get random trivia.

    我們還可以獲得隨機瑣事。

  • This is another endpoint on the API.

    這是 API 的另一個端點。

  • And then also this app will cache the gotten number trivia from the API so that if we should not have internet connection, so if we enable airplane mode here and come back to the app and get random trivia, it's not going to get us any new trivia, it's just going to display the lastly gotten cached trivia.

    此外,這款應用還將緩存從應用程序接口獲取的數字瑣事,這樣,如果我們沒有網絡連接,所以如果我們在這裡啟用了飛行模式,然後回到應用中獲取隨機瑣事,它將不會獲取任何新的瑣事,而只會顯示上次獲取的緩存瑣事。

  • Of course, once we enable internet, we'll be able to again get new trivia just like before.

    當然,一旦我們開通了互聯網,就能像以前一樣再次獲得新的瑣事。

  • This app has all of the core components, which you will be working with in your own apps on day-to-day basis, such as getting data from API, local cache, error handling.

    此應用程序包含所有核心組件,您在日常工作中會用到這些組件,例如從應用程序接口獲取數據、在地緩存、錯誤處理等。

  • For example, if we input ABC with a keyboard, you can do that.

    例如,如果我們用鍵盤輸入 ABC,你就可以做到這一點。

  • So input that, it says invalid input, the number must be a positive integer or zero.

    是以,輸入後,系統提示輸入無效,數字必須是正整數或零。

  • It has like input validation and all that good stuff, which you should have in production apps.

    它有輸入驗證和所有好東西,這些都是生產應用程序應該具備的。

  • And as for state management, we're going to use block, but you do not have to use block because as you will see later on in this course, as we progress, it will become apparent that the state management which you choose is really almost inconsequential because everything will be handled in different layers.

    至於狀態管理,我們將使用塊,但你不一定要使用塊,因為正如你在本課程的後面會看到的,隨著我們的進展,你會發現你選擇的狀態管理實際上幾乎無關緊要,因為所有的事情都將在不同的層中處理。

  • So the bottom line is do not worry if you do not want to use block in your apps, you do not have to.

    是以,如果您不想在應用程序中使用區塊,也不必擔心。

  • Clean architecture works with any kind of state management pattern, even something like simple change notifier with a provider will be just fine.

    簡潔的架構適用於任何一種狀態管理模式,即使是簡單的帶有提供程序的變更通知程序也沒問題。

  • And be sure to check out the written tutorial from the link in the description if you want to really go through this at your own pace, because this first part will be more about theory behind clean architecture, because we cannot progress forward in this course without first understanding the core concepts of clean architecture and why it's actually useful and why it does things the way it does them.

    如果你想按照自己的節奏來學習,請務必從描述中的鏈接查看書面教程,因為第一部分更多的是關於簡潔架構背後的理論,因為如果不首先理解簡潔架構的核心概念,以及為什麼它實際上有用,為什麼它以這樣的方式做事,我們就無法在本課程中取得進展。

  • And in the written post accompanying this first part, you have all of that available and you can go through it at your own pace.

    在第一部分所附的書面文章中,你可以看到所有這些內容,你可以按照自己的節奏來閱讀。

  • So let's first take a look at the clean architecture as it was proposed by Uncle Bob.

    是以,讓我們先來看看鮑勃大叔提出的簡潔架構。

  • So it looks something like this and really it doesn't tell us much when it comes to Flutter because like what is a controller, what is presenter, gateway, what is all of that, it just spits out a bunch of abstractions in our face and all in all it's a bit abstract, pun intended.

    它看起來是這樣的,但實際上它並沒有告訴我們什麼是 Flutter,因為什麼是控制器,什麼是呈現器,什麼是網關,什麼是所有這些,它只是在我們面前吐出了一堆抽象概念,總而言之,它有點抽象,雙關語。

  • Also, while the essence of clean architecture remains the same for every framework, the devil definitely lies in the details and we will have to adapt this general clean architecture to Flutter.

    此外,雖然簡潔架構的本質對每個框架來說都是一樣的,但細節決定成敗,我們必須將這種通用的簡潔架構適應於 Flutter。

  • So lo and behold, because now I will introduce to you the Resocoder's Flutter clean architecture proposal, yes it's an official thing now, which will demonstrate something, should I say more important than just some dependency flow and the onion, it will show you the data and call flow.

    現在,我將向大家介紹 Resocoder 的 Flutter 清潔架構提案,是的,它現在是一個正式的東西,它將展示一些東西,我應該說比一些依賴流和洋蔥頭更重要,它將向你展示數據和調用流。

  • It may seem like there's a lot to comprehend here but do not worry, we are going to get through this slowly one by one.

    要理解的東西似乎很多,但不用擔心,我們會一個一個慢慢講。

  • So the core thing here is that the whole app or should I say every core feature of an app, like for example getting number trivia, will be divided into three parts, three layers, presentation, domain and data.

    是以,這裡的核心是整個應用程序,或者我應該說是應用程序的每個核心功能,例如獲取數字瑣事,都將分為三個部分、三個層次,即呈現、領域和數據。

  • And actually the app we are building, this number trivia app, will have only one feature because it's a simple app, the only thing we do here is to get number trivia.

    實際上,我們正在開發的這款數字瑣事應用程序只有一個功能,因為這是一款簡單的應用程序,我們在這裡做的唯一一件事就是獲取數字瑣事。

  • So we'll have only one such division into folders.

    是以,我們只有一個這樣的文件夾劃分。

  • So let's actually create these presentation, domain and data folders right now.

    是以,讓我們現在就創建這些演示文稿、域和數據文件夾。

  • So let's open up VS Code, we are starting off with a completely new project here and I will enlarge this so you can see the folders even better.

    是以,讓我們打開 VS Code,從一個全新的項目開始,我將放大這個項目,以便你能更清楚地看到文件夾。

  • So inside the lib folder we are going to start off with creating a features folder because every feature as I said will have its own folder which will be divided into presentation, domain and data.

    是以,我們將首先在 lib 文件夾中創建一個功能文件夾,因為正如我所說的,每個功能都將有自己的文件夾,分為演示、域和數據。

  • So let's just create the folders and then I will explain everything more in depth.

    是以,我們先創建文件夾,然後我會對一切進行更深入的解釋。

  • So the feature name will be simply number trivia.

    是以,功能名稱將只是數字瑣事。

  • You can have feature like login or registration or something like that, you can have feature settings and so on if you have those things in your app, we have just one screen number trivia and that's it.

    您可以在應用程序中加入登錄或註冊等功能,也可以加入功能設置等,如果您的應用程序中加入了這些功能,那麼我們只有一個螢幕的數字瑣事,僅此而已。

  • In here we want to create domain, then another folder will be data and the final one will be presentation.

    在這裡,我們要創建域,然後是數據文件夾,最後是演示文件夾。

  • And with this we have the basic structure, the most high-level structure of our app created.

    這樣,我們就有了應用程序的基本結構,也就是最高層次的結構。

  • Of course just having features is not enough because what if for example you have something which can be used across multiple features.

    當然,光有功能是不夠的,比如說,如果你有一個可以跨多個功能使用的東西,那該怎麼辦呢?

  • Let's just say that you have also settings feature and even over you want to do input validation.

    比方說,你也有設置功能,甚至還想進行輸入驗證。

  • Well input validation for example just checking if the inputted text doesn't contain any numbers that's not really feature specific, it can be shared across number trivia, settings, whatever.

    例如,輸入驗證只是檢查輸入的文本是否不包含任何數字,這並不是真正的特定功能,它可以在數字瑣事、設置等方面共享。

  • That kind of functionality will go into the core folder.

    這類功能將被放入核心文件夾。

  • All right now that we have the basic folder structure let's continue on with this awesome diagram.

    好了,現在我們有了基本的文件夾結構,讓我們繼續看這個很棒的圖表吧。

  • Let's take a closer look at the presentation layer which is actually what you are already used to in flutter if you've done any kind of a flutter development before.

    讓我們來仔細看看錶現層,如果你以前進行過任何形式的 Flutter 開發,那麼表現層其實就是你在 Flutter 中已經習慣的東西。

  • So presentation is comprised of widgets so this is where all of the pages live for example number trivia page and this is also where you will have your own custom widgets and then it also has something called presentation logic holders which is either a block, a change notifier or really anything which you would classify as state management.

    是以,展示是由小部件組成的,這就是所有頁面的所在,例如數字瑣事頁面,這也是你擁有自己的自定義小部件的地方,然後它還有一個叫做展示邏輯的東西,它可以是一個塊、一個變化通知器,或者任何你可以歸類為狀態管理的東西。

  • You can even go the good old stateful widget route but I would really recommend you to at least go for change notifier but I really think that block is the best state management option for flutter out there but really presentation logic holders they're not all that important which you choose.

    你甚至可以選擇有狀態的老式 widget,但我真的建議你至少選擇變更通知器,但我真的認為區塊是 Flutter 最好的狀態管理選項,但真正的演示邏輯持有者,他們的選擇並不那麼重要。

  • We are going to choose block for this app and as opposed to what you may be used to these presentation logic holders so block or change notifier will really not do much by themselves.

    我們將為這個應用程序選擇區塊,與您可能習慣的演示邏輯持有者不同,區塊或更改通知器本身不會做太多事情。

  • They will only delegate all of their work down to use cases to the domain layer and so on.

    他們只會將所有工作下放到用例,然後再委託給領域層等。

  • Blocks or change notifiers will be really lean classes.

    塊或更改通知器將是非常精簡的類。

  • They will not have a lot of logic.

    他們不會有太多的邏輯。

  • At most you will do some really basic input validation inside of them and that's it.

    你最多隻能在其中進行一些非常基本的輸入驗證,僅此而已。

  • Everything else will be delegated to the next layer which are use cases or the domain layer.

    其他一切都將委託給下一層,即用例層或領域層。

  • Before we continue with the next layer let's just jump into VS Code and let's create the structure of the presentation folder right now so we're going to create new folder under that.

    在繼續下一層之前,我們先跳轉到 VS 代碼,現在就創建演示文件夾的結構,是以我們要在該文件夾下創建新文件夾。

  • It's gonna be called block.

    它將被稱為 "區塊"。

  • Again you can use anything you want and then pages and finally widgets which will be just widgets which we do not want to have directly inside the page because it would just clutter up the UI code.

    同樣,你可以使用任何你想要的東西,然後是頁面,最後是小部件,我們不希望直接在頁面中使用小部件,因為這會使用戶界面代碼變得雜亂無章。

  • The next layer we are going to take a look at is the domain layer.

    我們接下來要看的一層是域層。

  • As you can see in this call flow arrow the call flow will happen from the upward layer so presentation down so this presentation logic holder for example a block will delegate its work and call use cases which are from the domain layer.

    正如你在這個調用流箭頭中看到的,調用流將從上層發生,所以呈現層是向下的,所以這個呈現邏輯持有者(例如一個塊)將委託其工作,並調用來自領域層的用例。

  • So what is actually the domain layer?

    那麼,領域層究竟是什麼呢?

  • This is the inner layer which should not be susceptible to the whims of changing data sources or porting our app to angular dart.

    這是內層,不應受數據源變化或將應用程序移植到 angular dart 的影響。

  • It should be really platform independent and actually independent of anything else inside the app.

    它應該真正獨立於平臺,實際上也獨立於應用程序內的任何其他內容。

  • It will contain only the core business logic which will be executed inside use cases and then also business objects which we are going to call entities and by the way use cases are classes which encapsulate all the business logic of a particular use case of the app so for example we will have use cases for getting concrete number trivia right here which will be executed whenever we press the search button here so this is get those will be two classes get concrete number trivia and get random number trivia.

    它將只包含在用例中執行的核心業務邏輯,以及我們稱之為實體的業務對象,順便說一下,用例是封裝了應用程序特定用例中所有業務邏輯的類,例如,我們將在這裡設置獲取具體數字小知識的用例,每當我們按下這裡的搜索按鈕時,這些用例就會被執行,這就是獲取具體數字小知識和獲取隨機數字小知識這兩個類。

  • Of course in our app we will not have a lot of business logic and even the entity which will hold the number trivia actually they are gonna be pretty lean classes because we are not doing much in this example app but in your own projects when you are building something more substantial the domain layer is where the bulk of the code will be located and if you've been listening to me carefully I've said that the domain layer should be completely independent of every other layer.

    當然,在我們的應用程序中,我們不會有大量的業務邏輯,即使是保存數字瑣事的實體,實際上它們也會是非常精簡的類,因為我們在這個示例應用程序中做的不多,但在你自己的項目中,當你要構建一些更重要的東西時,領域層就是大部分代碼所在的位置。

  • Well I know that you probably cannot tell much just from this diagram but it seems that the domain layer is independent of the presentation layer but here it gets kind of fancy looking because the repository is seemingly inside the domain layer and also in the data layer right so what's up with that half of the repository is domain and half is in data no that's not how it is.

    我知道你可能無法從這張圖中看出什麼,但領域層似乎是獨立於表現層的,但這裡看起來有點花哨,因為存儲庫似乎在領域層內,也在數據層中,所以一半存儲庫是領域層,一半是數據層,這是怎麼回事呢?

  • The repository class is on the edge between data and domain layers and to allow for the independence of the domain layer we are going to do something called dependency inversion.

    存儲庫類位於數據層和領域層之間的邊緣,為了保證領域層的獨立性,我們將進行一種叫做依賴反轉的處理。

  • So what is dependency inversion?

    那麼什麼是依賴倒置呢?

  • I know that you may be getting some goosebumps because they're just scary words but dependency inversion is in essence very very simple and straightforward it's just a fancy way of saying that we create an abstract class repository which will define a contract of what the repository must do so for example in our app we will have a repository which must provide us with random trivia and concrete number trivia those are the two things which the repository just must do and that goes into the domain layer.

    我知道你可能會起雞皮疙瘩,因為這些詞太嚇人了,但本質上,依賴反轉非常簡單直接,它只是一種花哨的說法,即我們創建一個抽象類存儲庫,定義存儲庫必須做的事情的契約。

  • The domain layer does not care how the number trivia will be gotten it just cares that it will be gotten right this is all possible with an interface or because dart does not support interfaces we have to use abstract classes and then the other side of the coin or in this case repository is inside the data layer the data layer will define how the data will be gotten and managed and all of that we're get to that in just a short while but the important thing is that the repository in the data layer will implement the abstract class so it will have to conform to the so-called contract so that domain can really not care what's going on behind the scenes it just knows what kind of data it will always receive from the repository in this case it will be the number trivia so let's create the folder structure shall we inside VS Code the domain layer will have three subfolders entities which will be the number trivia entity which will simply hold the text of the trivia and the number of the number trivia then we will have also another subfolder repositories this is where the contract or the abstract class of repository will go and then also the last folder is use cases so use cases are get concrete number trivia and as you can see there was some server failure now so error handling works correctly but I don't know why there was a server failure but anyway now we have 42 so this is the concrete or get concrete use case and we also have the random use case and let's now move on to the data layer as you already know it contains repositories which implement the abstract classes from the domain so that they will have to just fulfill the contract defined by domain and then it also contains remote data sources local data sources any kind of data sources obviously go into the data layer usually you have one data source for getting remote data from the API and then you also have another one for getting local data in our case we will use shared preferences to cache the data locally and local data sources are also where you would have your for example GPS location code and all of that good stuff data sources do not have to just operate with databases they can also operate with the underlying platform or device and the repository is the brains of the data layer because this repository will decide when to cache, what to cache, when to get data from the remote data source, when to get data from local data source so for example if there is no internet connection we definitely want to get data the cached data from local data sources and you may notice that repositories output entities which kind of makes sense and again entity is just the number and the text of the number trivia really simple in our case but data sources do not output entities they deal with something called models and this nomenclature is really not all that important it doesn't matter how you call these things it's just that you know what those names mean and the reason behind having models is that transforming raw data which is for example JSON requires some conversion logic because we cannot work with JSON in our app we have to Dart objects but now let's think about this we definitely do not want to put our JSON conversion logic so to JSON and from JSON as we are all used to for example from built value or JSON serializable we do not want to put those conversion methods into entities and why is that well entities should be completely platform and data layer independent so for example if we switch from JSON to XML or to some binary data craziness we do not want to change the domain layer at all we only want to change the data layer when something data related changes but the domain should remain untouched therefore these models will be simple classes which extend entities and add some functionality on top of them and because they are subclasses of entities we can then simply cast them into entities and the repository will output the entity which does not have any additional functionality or fields added on top of it in the number trivia app since we do not have anything really difficult to do models will have only to JSON and from JSON methods but if you are storing something locally in an sqli database and for some reason you have to have the id inside the database stored inside the model you can also add some custom fields to the model not just methods in our app the remote data source will perform an HTTP get request to numbers API which is simply numbersapi.com and all of these links and all of that which I am explaining here is also available from the written tutorial so definitely check that out but here is numbersapi.com this is the API we will be using so as you can see we can get random trivia right this is what we are doing from within the app so this is what the remote data source will do it will perform get requests and then we have also local data source which will simply cache data using the shared preferences package and then these two data sources will be just a simple thing it will check whether or not the user is connected to the internet if there is internet connection it will always prefer to get fresh data from the remote data source if there is no internet it will get the cached data and it will also have a simple caching logic which is that we always cache everything as soon as it's gotten from the API so that if there is no internet connection it will always return the cached data the last cached data to be precise all right so let's now create the folder structure even for the data layer because the things below are not actually a part of our app these are some external things we do not care about them it's not a part of our code base and the data layer will be comprised of data sources, models and finally implementations of repositories so the repositories folder in data will hold implementations and the repositories folder in domain will hold the abstract classes or interfaces which are the contracts which the repositories implemented in data must fulfill and again this abstraction is necessary so that the domain layer can be completely independent of every other layer all right so this first part of this test driven development clean architecture flutter course was really theory heavy that's because something like clean architecture requires a lot of explanation because after all you cannot just start building a house without first planning how the house will look like you have to have at least some basic structure some basic drawings in place and these drawings were laid down in this first part so in the next parts we are going to actually get coding and doing test driven development and we are going to start off with this domain layer so if you do not want to miss that tutorial and more other tutorials like this definitely subscribe to this channel and also join the notification squad by hitting the bell button to make sure you grow your flutter skills because here on resocoder i am determined to provide you with the best app development tutorials and resources out there also make sure to check out the written tutorial available from the link in the video description to go through all of this at your own pace you will highly benefit from reading the written tutorial if you want to learn the most about clean architecture which i'm sure you want to do if this video helped you with clearing the concepts of clean architecture give it a like and also share it with our developers who will surely benefit from this too follow me on instagram i go under the name resocoder everywhere leave a comment if you have anything to say any suggestions or questions stay tuned for the next part in which we are going to finally start writing code doing test-driven development and see you in the next video you

    領域層並不關心數字瑣事將如何被獲取,它只關心數字瑣事是否被正確獲取,這一切都可以通過接口來實現,或者因為 dart 不支持接口,我們必須使用抽象類,然後硬幣的另一面,或者在本例中,存儲庫位於數據層內部,數據層將定義數據將如何被獲取和管理,所有這些我們很快就會講到,但重要的是,數據層中的存儲庫將實現抽象類,是以它必須符合所謂的契約。是以,讓我們在 VS 代碼中創建一個文件夾結構,域層將有三個子文件夾實體,其中一個是數字小知識實體,它將保存小知識的文本和數字小知識的編號。最後一個文件夾是用例,用例是獲取具體的

Keeping your code clean and tested are the two most important development practices.

保持代碼整潔和經過測試是兩個最重要的開發實踐。

字幕與單字
由 AI 自動生成

單字即點即查 點擊單字可以查詢單字解釋