Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranî)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
So lots of the early testers of this course ask me whether I was going to cover the solid principles.
And at first I wasn't thinking of doing it, but because I got so much request for it and to know how
it fits in with my coding commandments, I decided that it would probably be worthy of some bonus material.
So here are the solid principles originally originated by Robert C. Martin of clean coding fame and
other books, and just generally being a behemoth of the space.
So a little word of caution, and this is something that Robert C. Martins has himself in his original
paper on the solid principles is that following the rules on the patent won't teach you how to paint.
And this is important.
You can't just follow the rules and expect to be an amazing programmer.
There is lots of skill involved.
It's a craftsmanship and you need to learn it with experience.
And if you don't know when to break the rules as well, that is a problem.
So these rules are to be followed with caution and to be done with skill and applied judiciously.
So let's have a look at the single responsibility principle, the source of the solid principles.
This is very straightforwardly already in amendments.
I think it was point three or something the class should have.
Only one reason to change should have ultimately only one responsibility.
I don't think we have to dig into this one too much.
It's a very good tenet of object oriented programming in general, and it's important to note that all
of these principles aim to deal with change management.
If you have changing requirements in the world and you're writing software for a changing requirements
world, then you want your software to be flexible and allow you to easily adapt to new requirements.
So all of these are trying to aid you in that purpose.
So having a class responsible for just one thing aids you in that purpose by allowing you to know where
to go to make that change and also to have changes destabilise as few things as possible.
The open closed principle.
Now, this is probably the crux of the solid principles, at least as Robert C. Martin puts it forth.
And it's also the hardest to understand.
So, at its core, open for extension, but close to modification, what does this mean?
Well, it ultimately means that you can create subclasses or you can create extensions of an interface,
but without modifying the stuff that people are depending upon.
So we're closing down the interface so that we can easily depend upon it.
But then we're allowing extension of it to add new functionality.
So attempting again to make things easy to change by adding functionality through extension, but hard
to break by keeping it closed for modification now, how do we typically do this in something like C-sharp
or unity?
Well, we typically would use interfaces because we would rarely modify the interface that's closed
for modification.
But we would implement extensions or implementations of the interface, which allow us to implement
change.
And the same thing with abstract classes, you might make the abstract classes interface close for modification,
but open for extension.
So let's take a look.
As an example from the programming pattern we've been using, the strategy pattern is a classic example
of you implementing the open closed principle in the previous example where we had just the ability
runner and it worked on the basis of a Switch statement or an enum, then obviously this was a problem
because if we wanted to make any changes, we had to go and change the ability runner.
So this was both open for extension and open for modification.
Not what we wanted.
So using the strategy pattern, we pull out an interface for the ability.
Now that interface is closed for modification.
We very rarely going to change the number of methods on that interface and the parameters to that interface
methods.
So that's closed for modification, but open to extension because we can add in new abilities really
easily, and it allows us to adapt to new gameplay requirements.
Our game design decides, Hey, we need this new ability.
You can easily go and add it by extension.
So the next thing we've had S.A. of our solid principles, we now have the L, which is the list of
substitution principle named after Barbara Lisk of who states it like so that subclasses of this is
how it is stated.
Sometimes I think it's been stated by Barbara Lisk, often a bit more of a mathematical sense, but
here is the crux of it that subclasses should be substitutable for their base classes.
And you're probably looking at this and going, Why is this even a thing?
This is obvious.
You know, obviously, if I have a subclass, I should be able.
To substitute it for the base class, that's entirely the point.
Well, yes, I mean, obviously the interfaces will be substitutable, but the point is they also need
to be behaviorally substitution also.
So an example here is with rectangles and squares.
So we've got a clients that might have access to a rectangle class and that rectangle class has a width
and height.
Now you might easily say, well, square is just a rectangle.
It's a rectangle where the width and height are equal.
Cool.
That sounds that sounds like a reasonable thing.
Now on our rectangle, we've obviously got set width and height and get width and height.
And that seems reasonable.
So when we're using the rectangle, we might happily say, let's set the height and set the width,
and then we can assert that the height that we set is actually the height that we get back.
When we do it, get height seems reasonable enough.
The problem is we inherit a square, which also seemed like a reasonable thing to do.
It has the same interface, but to do this because we've got this extra height and width property that
in a square, we need to make sure that the same we override their settings so that width and height
always get set to the same.
And suddenly we have a problem because if we substitute a square into that client code that we've got
over here on the slide, this asset isn't going to be true and we go and set the width to three.
It sets the both the width and height to three and so overrides the value that the client was expecting.
And so here, apart from the programmatic interface that we have to this rectangle class, you've also
got some sort of implicit interface about how it should work.
You've got the implicit that if I set something, I expect it to still be there when I get it back.
And so this fails in terms of substitution, lisk of substitution and all sorts of bugs can arise from
this.
This is a very simplistic case.
However, there are many such cases that are harder to find, and one typical example in object oriented
programming is equality, where equality gets defined, redefined further down the inheritance hierarchy
and can break when you substitute a child class in for a parent class.
And now I'm not going to go into details of how that breaks down.
I'll leave a link in the resources to a discussion of equality and lack of substitution principle.
But it's interesting.
Further reading If you want to go down that rabbit hole now interface segregation, this is the eye
of solid.
What does this mean that many client specific interfaces are better than one general purpose interface?
So, for example, imagine we have a health component that we've been working on in this course and
was being used in potentially multiple places in the UI to display the health, but also by combat to
subtract from the health.
Now what we're saying is that those are two very different use cases by two very different clients.
So perhaps you'd be better off having an interface for each, maybe an eye health display to facilitate
the interface for the UI and an eye damage ball for combat code.
And the reason this is a good thing is that it allows for all sorts of dynamic JBL's later down the
line.
It allows us to swap the health display to something else.
It also means that there are fewer opportunities to accidentally get extra dependencies in there.
So, for example, the UI accessing some methods that it shouldn't and later causing problems when we
need to refactor our health components.
So it keeps those dependencies kind of segregated in this interface segregation principle.
And finally, the D of the solid principle is dependency inversion.
What does this mean?
This is typically implemented with interfaces so depend upon abstractions do not depend upon concretions.
Now the idea here is that suppose you have your gang code and you are depending on a concrete and you're
depending on a concrete system such as the Unity audio subsystem or maybe your asset pack super dialogue
system x that you've downloaded from the Udemy Asset Store.
Now everything is well and good until you realize that, oh no, you know what I wanted to use actually
was Super Dialogue System Y, because it has this really cool feature that I need and a DNC audio system
just isn't quite cracking.
For me, I now need the f mod subsystem to do the work much better.
Now you've obviously got a headache because you've hardcoded all of the interfaces of the U.S. audio
system and the super dialogue system into your game code, and you've got to go and change a whole heck
of a lot of code in order to swap these two out.
So the dependency inversion principle would say instead of Japan.
Running on those concrete subsystems, why don't you depend on an interface instead?
So you depend on a dialogue system interface in your game code and an audio system interface, and that
would define how you're going to interact with these subsystems.
And then the subsystems would all inherit from their relevant interface.
And now swapping them out becomes a doddle because they interfaces are the same.
Now, obviously, you can't make the unity audio subsystem conform to your own subsystem interface.
So for this kind of thing, we might use the adapter pattern, which is a little bit like the decorator
pattern in its structure.
But the idea is that we would put a little components, a little object in between the implements,
the audio subsystem interface and uses the audio that basically acts as a translation unit and translates
from your audio subsystem interface into the unity audio subsystem interface.
That is a situation when you can't change the actual code itself.
You can add those little adapters in again.
If you are interested in the details of the adapter pattern, do go and have a look at the resources
because of links to refactor guru there, where they could do a very good explanation of that pattern.
So those are the solid principles, the single responsibility where we say a class should do one thing
open closed, meaning that we should allow extension of interfaces but not modify those interfaces too
much.
The list of substitution principle where we're saying that behaviorally, if there is some sort of implicit
contract on a parent class, we should obey that in the child classes, the interface segregation principle,
which means splitting out interfaces for different clients.
So there's less reasons to change those.
And the dependency inversion principle, which allows us to swap out large bits of concrete implementation
to keep our game code or any code really less fragile to change.
So hopefully you found that interesting and you've taken away some points that you may want to use in
your own projects.
If so, please do go and share them in the discussions.
I would love to hear your thoughts.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.