 Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green, and with me is Phil Jepixi. Hey, Robert. Hey, Phil. How are you? Good. We're getting towards the end. I know. We are continuing our discussion of design patterns. Design patterns. We've done the behavioral. Yep. We've done the creation. Creational. And we are now going to do the structural. We are going to do patterns that are structural, doing them all. Categorize as structural patterns. True. So let's review. Quick review of the different design patterns. Behavioral, that's how we communicate between objects. We talked about the command patterns. We talked about quite a few behavioral patterns. The creational, how do we instantiate objects? We want to extract that away from our calling code and just have something to work with. I haven't created a new car each time. And we really covered the Singleton and then the umbrella corp of the factories. Right. And then structural is what we're moving into. And this is how we compose and relate different objects together. And we're going to talk about three patterns. Two in this episode. And then that is the adapter and decorator. Fassad. Adapter and facade is this one. Fassad is this one, right? I have an alphabetical order on my screen. And it really is not done in alphabetical order. And then the final one, our next episode, we'll talk about the decorator. OK, cool. So let's talk about the adapter and facade. And I really clumped them together. Because whereas academically, they're different. In practicality, they pretty much do the same thing. But it's just how they operate and what they're operating on that distinguishes them. So let's just talk about the simple adapter. We really want to make something look like something else so we can use it. The example I use all the time for those of us with gray hair. We remember two prong outlets, right? And dad would come home with a three prong plug. And you're sitting there looking at the outlet. You're holding the plug. So we did whatever a future engineer would do. We broke off that third prong, plug it right in. Now what you're supposed to do is get one of those adapters. And get the thing that you plug onto it. You plug into it. It's called an adapter. And it's got the little wire hanging off of it. Put that wire attached to the screw in the faceplate. No, I never did that. No, I thought I was broken off. But then now I can plug it in. And it really is a two-way adapter, right? I'm making the plug work into the two prong outlet. But then electricity then can flow into whatever device it was I'm plugging in. So let's talk about, before we get into the code, let's talk about why we might use this in real life. And let's go back to the weather app that we've been talking about through several of these episodes. You've got a button on a form. You push the button, and it's going to, for a particular city, bring back the temperature, the forecast, bare-mounted pressure, whatever, weather stuff. Well, we talked about the command pattern. Going to get that stuff. We talked about the factory pattern of how do we instantiate weather bug, or the weather channel, or MSN weather, or whichever client we're going to use, or service, we're going to use to get this. But now we're going to deal with the problem of, unless they all follow the exact same interface, calling them each will be a little different. So if I want to get the temperature from weather bug, maybe the call is called get temperature. If I want to get it from the weather channel, maybe it's called current temperature. And it's a property and not a method. So what we have to do is we have to take that three prong plug and make it fit into a two prong outlet. We do it with an adapter. And adapters actually can work both ways as the electricity flows. Let's say when we call get temperature, we're getting a number back. Sorry, when we're calling it on weather bug, we get a number back. But maybe on the weather channel, it's a string, because it's got the F or the C. And we have to parse that. Well, we don't want to have to have that inherent knowledge in our application to know exactly how to talk to this return type. Because then what we have done is we have hard-coded an implementation detail into the caller, right? So what I want to know is I want to be able to say, I'm always getting back, maybe it's an object, a custom object that has the temperature as an integer or a decimal, if you care about the fractions. And in enumeration, it says Fahrenheit or centigrade. And you always want to get that same type back. Well, that would be an adapter. Right, yep, okay. So I always like, and we've talked about this on many shows, I'm gonna say it again, in case you're picking up the series right here, I don't use domain-specific code when I do examples because if we did banking, for example, one of you is probably an expert in banking and would call me out, I'm not doing the domain correctly. So I actually picked Rocky and Bullwinkle as my domain because, hey, I'm from that era and I don't think you can call me wrong for talking about a talking moose and a flying squirrel. Talk about moose and squirrel, it's never wrong. And Natasha and Boris. So we have, well, let's go into definition of what a moose is. And again, I don't have the comment in here but you've seen the comment in many other examples. You should not have all these classes on one file. That's just bad form, makes it hard to support. But for the sake of teaching, we keep it together. So I had this moose and it implements an iMOOS interface and it has two methods, run and charge. I have a bad guy and all bad guys can do is driver shoots and a flying squirrel that can fly or drop acorns. And that's fine, those are the characteristics of those. This is the get temperature, get temp, get current conditions, whatever the call is. Right. Now I wanna work on these things collectively in the collection. So I wanna be able to just call, chase, flee or attack or defend some common method. Get temperature. What I have to do is make each of these guys look like some other interface. We usually start that with creating a new interface. And for this example, I just call it iCharacter and it has three methods. Chase, flee and attack, right? So this is my get temperature, get forecast, get barometric pressure, whatever. Now we have to create an adapter. So let's look at the moose adapter first. So the moose adapter implements iCharacter. Takes in an iMOOS constructor and then it maps my common interface methods to the specific methods of that moose. And this is the key point of this pattern, it's a mapping. It is. You always want your characters to chase, flee, attack. Yes. But the way the moose, the squirrel, the bad guy are written, they don't necessarily call it chase, flee, attack. It's run, charge, it's drop, acorns, it's whatever else it is. You're not gonna change that underlying code. Right. You're just gonna put an adapter on top of it so that when you use these, they chase, they flee, they attack and then this code here is the adapter that maps what you wanna call it to what it's actually called to just make it easier for you to not have to remember what is it that a moose does, a moose chases. Right. You just create the adapter and now from now on, you just call moose.chase and it does what it does. When you don't call moose.chase, you would call iCharacter.chase. iCharacter.chase, right, right, right, sorry. Yes, yes, yes. And it's two ways. So let's say that run actually returned a decimal for the moose. Well, we could certainly truncate that into an integer and make it look like what we want to get back out of it. Right. And it's the typical problem that you mentioned with the weather app, right? So now I've got all these different things and could I solve it without this pattern? Yes, I could write a lot of code. I can make an array list, which is not strongly typed and I could return this object or these objects in an array list and then each time I want to call something, I'd have to check the type. So I've got a switch statement in there saying if type is moose, then I now have to know in my head that chase actually equals run. Right. And I have to go on to do that in code. So what this does for us is saves us huge amounts of time on the road. Right, you just do the mapping once. And then you forget about it. You just call what you want it to be called, get temp, chase, whatever it is, you get to decide and then you just call it once because you created the mapping. And then if you have to change or if you have to create a new one, you just go change the adapter once. Right. Awesome. Yep. So you can have multiple adapters, right? Yep. Create a new, you find a new weather service you want to try out. You just create a new adapter, your factory then returns that adapter and encapsulates that particular weather app and you don't have to change any of your underlying code. Right. So all that testing that you've done, whether it's the production people testing it or actually QA testing it, you don't have to worry about changing the code and risking introducing the app. It also makes it a lot easier for you to maintain the app because it may turn out that the free weather service you were using is no longer free. Right. So you got to go find a different free weather service and it's not going to have the same methods and return the exact same data, although it's weathered information, it's not going to be called the same. Yeah, so the perfect. So now you don't have to, sorry, just to finish that. You don't have to change your client code. Right. You just change the adapter. Correct. Or create a new adapter. Or create a new adapter. Sure. So a real life, the thing that happened to me on where the adapter saved basically my butt, we were building an e-commerce site for a customer and we were very close to release. And we, back in the classic ASP days, VB6, DCOM and all that kind of stuff. And that wasn't really into design patterns that much back then. This was, you know, 1990s. And got a call from the CFO and he said, we had to switch our e-commerce provider. And we had, I think it was like five or six weeks until release. And we had, we had nued up every single time that we needed to use the e-commerce provider to do an address check, to do a credit card check, to do a charge, everything else. So we glued that particular implementation into our code. Now they said you have to use this other one. The interface was completely different. The return types were completely different. And I'll be honest, I panicked, right? I'm like, what am I going to do? And I talked to a buddy of mine who's been doing this for a lot longer than me. And he said, we'll just use an adapter. And so, you know, long, long before the Google search of today got the original Gang of Four Patterns book, Reddit, at least that chapter. And I went, oh, yeah. So I created an adapter around a new e-commerce provider. And all I had to change in my code, this is still bad because I'm changing code that was tested, but I just changed what I was newing up. I was creating an instance of the adapter instead of the old credit card provider than all the method calls were exactly the same. Because you just made the new one look and behave like the old one with the same names, same return types. And then you just wrote the mapping layer. Sweet. Yep. So this is a great pattern. I use this a lot. Think of it if you're using a third-party control and you want to switch vendors, right? Because you don't want to have vendor lock-in or whatever the reason is, doesn't matter. Well, again, you can just write an adapter to make that new third-party control look like the old one. Because you're not going to get in, you don't have access to a third-party code to make those changes. Right. Cool. All right, so the facade in the second half of the screen is much like an adapter. Although, what the goal for the facade is to provide a simplified interface to usually disparate systems. So let's go back to your weather app. Let's go back to your weather app example. OK. Put it back on us. Sorry. I was going to reach over and hit the keyboard, but I didn't. Let's go back to your weather app example, right? And what you've learned is that you've got the adapters in place for all these different weather apps. But you're on the market, and what you've realized is that I'm not going to use any names because that won't be getting mad. But Weather Service A is really accurate with the temperature, but it's terrible at doing a forecast. Weather Service B is really good at doing a forecast. And Weather Service C is really good at doing humidity and air quality. Well, you don't want to have to create all three of these, and remember which one to call. So what we want to do is we want to make a simplified interface, probably the same interface that we're using. It says get forecast, get temperature, get air quality. But now that facade says, oh, you want to get to temperature, we're going to go to Service A. You want to get the air quality, we're going to go to Service C. So whereas they're very, very similar, the adapters and the facades, an adapter typically just makes one thing look like something else, a facade simplifies disparate systems into something that you need. So we've talked a lot about the e-commerce example. Let's use that, right? So bigger companies usually have multiple different systems, one to control inventory, one for purchasing. Maybe there's an interface with some delivery carrier, UPS or FedEx or let me try to name them all so I don't get somebody mad. And as a developer, I want to create a system that is very simple for the users of my system to do what they need to do. Let's look at the template method, right? Where we're calling into shipping or inventory. Do we have the inventory? OK, pick it. Let's go into another application to do the packaging, another application to schedule the shipping. Well, as a developer, I don't want to have to remember, how do I call into this Java API to do inventory? And I've got to figure out how to do a web client or a REST client to do all this stuff going against Java. Remember what the URI is and everything else? No, I'm going to create a simplified interface that says check inventory, pick inventory, and maybe pass in a product number. So this facade then says, oh, you're calling this? Fine. I know that I need to take it to this system. I'm writing that heavy lifting code once, working hard up front so I can be lazy down the road. And so it's the same for all these different systems. And that's the facade. So that's why I decided to put them together. Yeah, they are similar. They are very, very similar. And really, it's just an academic difference as to whether you're just making one thing look like something else or taking pieces of something to simplify. All right, so let's say, actually, let's go this way, because we've all seen code like this. Let's say we have some application called iOverDone. And we've got methods that say do something or do something else or do something again with those old school parameters X, Y, and Z. Here on line 16, they obviously ran out of alphabet letters started over at the beginning. OK. Robert, what do you think those methods do? Something. Yeah, they do something. So now I have to figure out what each of these methods do, what the parameters mean. And then if I need to use this system, maybe this is the inventory system. Maybe do something else is actually checking inventory. But if I have to do that research each time, then it's going to slow me down and add friction. OK. So what I really want to do is take the iOverDone and the iConfusing, and this was written by somebody who just learned to add methods through the automatic refactoring tool in Visual Studio, because you can tell the name is Method 1 and Method 2, and make a simple interface that just calls the methods that I need off of these two systems. OK. So we do our research. We come up with a better API. And again, let me put some line breaks in there. And we learned that there's two functions we need with some overloads. The first is add three numbers. Maybe this is check inventory. Then we have three overloads with add and then multiply. Maybe this is pick inventory. And we've got some extra parameters because picking books is different than picking fragile, which is different than picking groceries. And I've named the parameters more appropriately for what they mean. All right. So now I have to somehow map this API to those other two applications. And when we look at the code, we really are just doing that map. It's just like an adapter. OK. Yep. Right? So add three numbers, takes into three numbers, executes the execute method on the confusing API, which we have learned through reflection or looking at source code or some other documentation that's just adding those numbers together. And then the same is here. Add and then multiply. And we've learned what the overloads do. And we call. But you're calling on a different interface. So you're now combining those multiple interfaces into a single one and renaming it. And renaming it. And dressing it up, I can certainly change your return types as well. So if I had, let's say, the temperature, again, comes back as a string. But we needed to be an integer with some sort of enum. We can handle it in tuples in C sharp 7, but we could just also use a simple object to do that. When we look at the test for this, we can say that it's really easy to look at this code and know what that interface is doing. I could write the same test. It probably would have been a good example to use the old confusing APIs to do the exact same thing. And we would see things like system.test.execute with some numbers. And if we had three and three in there, and it was six, is it adding? We think it is, but we don't know, right? Yeah. Why don't you just rename it so you know what it's doing? Exactly. That's all, yeah, that's what we're doing here. And that's all it's doing. These are great patterns. I use them all the time, especially if I've got a third-party control or a set of third-party controls. Or even just going as we've got a situation with a customer right now where we've got some EF6 code, we've got some EFCore code, we've got some straight ADO. And what I've done to make it simpler for my team is I've written some facades in there to say, get this data, get this data, get this data. It really simplifies it. Again, it's more work up front, but then afterwards, you're designing the API yourself. I would say it's not more work up front. It is work up front, but you would have to do it. Well, it's more work up front than just diving in. It's work up front. That's true. You do have to make. It saves you a bunch of time and gives you the ability to write code that's more likely what you wanted it to be. It's a more correct code. And so when I was saying I would correct you that it was more work up front, it is because you have to create the facade. But that research you have to do to understand the facade, you would have to do it every single time you're called into one of these systems. So you're saving a ton of time by doing this. Yeah, definitely. And we always have to imagine that the next person looking at our code is an ex-wielding psychopath. And if we leave a really bad API for them to use, then they're going to come after us. Now in reality, who is the next person that will look at your code? You. It's almost always you, right? And you look at this code. Days, weeks, months later when you go, what the heck? You go, this is terrible. Who wrote this? And you go look at the commit login, realize it was you. And you go, oh, no, sorry, this is great code. I love it. I went a long weekend. I got to fix this. Yeah, or you come back weeks or months later and you say, what was the method again to do that? Yeah, was it execute or was it do something or do something else? Right, do this return a double or an anti? I keep forgetting. Yeah, yeah. Sweet. So. All right. Well, that's the adapter and facade. Cool. Hope you enjoyed that. And we'll see you next time on Visual Studio Toolbox. Thanks for listening.