Lecture thumbnail 0:00 / 0:00 So in our discussion of the adapter and decorator design patterns, I showed you an example where you’d

actually build an adapter decorator.

Now, what I wanted to show you is a more real world example, something that you would actually use

in the real world.

What we’re going to be talking about is we’re going to be talking about strings.

And specifically we’re going to build a class called STR.

Now, STR, as you can see, it’s lowercase here.

The reason why I’m keeping it lowercase is because since this is going to be a surrogate for a string,

I’m not going to be able to use Var.

I’m not going to be able to say var x equals something and have it use the STR class.

So instead of var, we’re going to have STR like this.

And that’s something that we’re going to support in just a moment.

So lowercase is okay here because I’m building something that’s effectively a system type.

Now of course you can make it sort of you can make it capital STR and then just put a using statement,

but then you’d have to add it everywhere.

And since we’re not modifying the compiler, I’m just going to keep it like this.

So the goal of STR is to represent an Ascii string because the ordinary net strings are UTF 16, which

is okay in terms of compatibility because then they support all the possible languages that you might

want to use.

And by the way, you can also use Unicode inside the source code as well if that’s what you wanted to

do.

But let’s imagine that you’re working with a finite domain.

Let’s suppose that you’re dealing with just Ascii characters and you want the speed, you want the performance

of Ascii characters and Ascii strings.

You maybe want things like mutability, being able to modify individual letters.

Maybe you want a substring that doesn’t generate a new string, maybe you want all of those things.

And so that’s why we’re building this adapter slash decorator slash, I don’t know.

It’s difficult to quantify this.

I’m going to show you what it looks like, though.

So essentially what we’re talking about with Ascii strings is just having a buffer of bytes.

So a single character takes up just a single byte.

And that’s an invariant.

So here I would make a protected read only byte array.

Let’s call it Buffer.

I’m also going to use Resharper annotations, jetbrains annotations, rather.

You can you can see them up here.

So I’m going to decorate this with not null just so that the static analysis tool knows that we’re never

going to have a null in this particular field.

So we need a default constructor constructor which takes no arguments here.

I’ll initialize the buffer.

I’ll say buffer equals new byte array.

Just just an empty byte array like so.

But of course the whole point of this is that you can initialize this with an ordinary string, the

UTF 16 string that you get by default in Dotnet and you convert it into an Ascii string.

So you have public str which takes a string.

And here we say buffer equals encoding dot ascii, Ascii dot get bytes, get the bytes from the string.

And of course what’s going to happen if you provided some sort of Unicode string, like a string with

Chinese or Japanese characters, for example, is it’s going to mess things up, it’s going to break

and your byte array is going to contain just just garbage because, you know, those those elements

don’t fit into a single byte.

So the whole point of this class is to be usable with Ascii text only.

Another thing that we want is we want a sort of copying constructor in the sense that we want to specify

the buffer explicitly, but this is going to be used internally, so I’m going to make this protected.

So that’s going to be an STR, which takes a byte array called Buffer.

And here I’m going to say this dot buffer equals buffer.

So these are our constructors done.

Now, what we obviously want to do is we want to be able for this thing to masquerade as a string because

it’s a it should be convertible to a string.

For example, if you want to print it out on the command line, you have to turn it into a net string

because STR is just this, this adapter slash proxy slash decorator, whatever.

So the simplest way is we can, first of all define two string, and here I can reconstitute the entire

string so I can say encoding dot Ascii dot, get string and get the string from the buffer.

That way we’re going to have our original string back.

Of course, it would be really nice if we had some sort of implicit conversions from a string.

So this is also possible in dot net thanks to implicit conversions.

Operator.

So we can have public static implicit operator STR so you automatically get an str from a string s like

so and here you can return a new STR, which just just takes the string and initializes the whole thing

and just, just continues to work with it.

By the way, what we can do just to demonstrate that the whole thing works is we could, we could be

writing a few tests just to, just to make sure that everything kind of functions.

But I’m going to leave this out.

So in the source code, you’re going to see lots of tests on this exact thing, but I’m going to leave

those out because it’s just going to consume too much time.

So we’re going to continue with this idea of what kind of features do you want to have?

Like, for example, you want to have equality, you want to be able to compare strings.

So here what I would start with, of course, is I would start with generating the equality members

using whatever ID you actually prefer to be using.

So this gives you lots and lots of overloads.

You get equals and you also get the weakly typed and the strongly typed equals.

And here you can see that this line is problematic because that’s not really how you compare, that’s

not how you compare arrays.

So if you want to compare the buffers, which is what we want, in this case, we would do something

like the following.

We would say we would first of all take the buffer that we have and we would cast it to an I structure

or equatable.

The naming is a bit insane.

That’s not my fault.

It’s the dot net framework.

Just just giving it names like I structure or equatable that means nothing to me.

But basically it also has an equals where you specify the other buffer, but there is a flag here.

You can do structure comparisons, dot structure, equality compare, and this makes sure that the comparison

is done sort of element by element.

So you’re effectively comparing two arrays and this is the most correct, shall we say, way of doing

it.

We also have the equals and not equals operators.

You can see that they are just reusing equals.

So there isn’t really much that needs to be done here.

One thing you can implement is you can implement equatable of STR.

So that’s an interface which tells you basically that this string is can be tested for equality with

STR and that can be used in some algorithms.

It can also we can also do icomparable.

Remember, comparable doesn’t just tell you equality, it tells you the ordering relationship which

one comes before the other, sort of the less than greater than operators and so on.

I’m not going to mess about with this too much.

Now, one thing that we want to have is hashCode obviously taking the hashCode of the buffer isn’t really

the best way because we want this to operate exactly as a string.

So we’re going to call to string here and then get hashCode of that.

So the hashCode of STR is exactly the same as the hashCode of the underlying string.

That makes sense, I think.

Okay, so what else do you want if you want such a wrapper?

Well, how about concatenation?

How about concatenating these STR strings as well as ordinary strings?

How can we actually sort of implement this whole thing?

Well, you might be forgiven for thinking that there’s going to be some sort of state space explosion

here, because remember, we have different cases.

We have str str, we have str plus string, we have string plus str, and we have string.

Well, string plus string is obviously part of net.

So we’re not going to see three cases here.

And the reason for that is implicit conversion operators.

So really when you do STR plus string and we know that string can be implicitly converted to STR, then

it’s going to is going to be automatic.

So all we have to do is we have to implement STR plus STR, everything else we’re kind of getting for

free here.

So how do we implement str str?

Well, as you may have guessed, you have to concatenate the two arrays.

So let’s do this public static str operator plus where you take str first and str second.

And what you do here is you make a new.

Buffer.

So you say var bytes equals new byte array.

And here the calculation for the size of the array is the sum of the sizes of the first and second parts.

So it’s first dot buffer, dot length plus second dot buffer, dot length.

So that’s the size of the array.

Then you copy the first and second part.

So the first part goes at position zero.

So first dot buffer dot copy two.

So we copy it two bytes at position zero and the second part gets copied with a position that is offset

by the size of the first array.

So second dot buffer dot copy two.

So here we specify bytes and first dot buffer dot length.

There we go.

And we return a new str constructed from, constructed from that set of bytes.

So that’s why we have that protected constructor, which actually takes a byte array because we’re using

it here.

So this is how you would construct the whole thing.

I could go on in terms of the kind of functionality that you have here.

So for example, when you’re taking a substring, you probably want to return a span.

For example, if you wanted to, let’s say, modify the individual characters, because this time around,

this is a mutable string.

Obviously, the buffer here I’ve I’ve set it to well read only actually only affects the the variable

itself.

We can modify the buffer any way we want.

So typically what you could do is you could make an indexer, for example, so you could say public

char, this which takes an INT index.

And what you would do here is for the getter, you would just obviously cast the thing to a char buffer

at index.

Remember, even though a byte is a smaller or equal to a char, what happens in the real world is bytes

are not signed.

And so I think I think the reason why this is happening is due to the sign conversion, but I’m not

sure anyways.

You have to have this cast.

I couldn’t write it without it for some reason.

Not very intuitive, especially coming from C plus plus world and you can have this header.

So here you can say buffer at index equals and then once again you take the value and you cast it to

a byte so as to put it into the array.

So this is how you can make mutating, mutating parts which actually change the individual characters.

Obviously it doesn’t allow you to insert a string in the middle of this particular string and modify

it, sort of expand the array because actually array operations of this kind are particularly painful.

And you this is if you want to have insertion something like a string builder, for example, then that’s

a different story.

So all I’m doing here is I’m making a string.

I’m making just just the same way as as an ordinary string, but with additional benefits.

The main benefit, of course, is that you have an array of bytes where a single letter takes up a single

byte.

So if you’re working with, let’s say, Cuda, you want some Cuda algorithms where processing happens

on the GPU, it’s a lot easier to lay out your data when you have this predictability because if you

have an indoor minute size of a character, then you cannot write reliable algorithms.

So this is just a real life example of something that I use a much, much expanded version of this for

my purposes.

And this is just something that you sometimes need to build in order to accommodate certain features.

In this case, it’s like it’s not progress, it’s regress because Dotnet is so progressive, it supports

Unicode.

And obviously you have, you know, in the world of C plus plus, for example, people are really suffering

due to the lack of Unicode.

But here the situation is different.

Here I’m giving you Unicode so I get UTF 16 by default and I don’t really want it.

I don’t really need it for my particular kind of work that I do.

So here I kind of downgrade a C-sharp string into this this STR concept.

So that’s all that I wanted to show, just just a kind of more real life example of an adapter slash

decorator slash proxy.

It doesn’t really fit any single one design pattern.

It’s more kind of a universal thing because, well, eventually you have all sorts of these crazy interactions.

Like, for example, not only would you implement Equatable of STR, but it also makes sense to implement

equatable of string obviously, so that you can, you know, compare with strings more efficiently.

Of course you have implicit conversion operators which which are okay, but, but really like here for

example, you would just, you know, just reuse existing functionality so you would return.

So you would obviously compare to string with other.

So stuff like that, fairly obvious stuff.

But you can see that you cannot just say this is a proxy.

You cannot just say this is an adapter.

It’s like all of those things at the same time and at the same time it’s also adding its own behavioral

functionality so you wouldn’t be able to classify it into a single design pattern or a single kind of

category, but it’s taking on some of.

Those ideas and putting them together to good use to to produce a piece of functionality that in my

particular case, I need for my calculations.

Play Stop Play Play Play Play Play information alert