This course is focused on integrating the design patterns we've studied into a practical project: building a smart home system. Throughout this course, you'll learn how to create and adapt various smart home devices using the Factory Method and Adapter patterns. By the end, you will have a solid understanding of how these design patterns can make your smart home system more efficient, modular, and easier to maintain.
In this unit, we explore two essential design patterns: Factory Method and Adapter. These patterns help us create and adapt devices within a smart home system. To effectively implement these patterns, we will build the devices using the Factory Method and then adapt these devices to interact with other parts of the system using the Adapter pattern.
-
Factory Method Pattern:
- Purpose: Encapsulates the creation of objects, making it easier to introduce new object types without altering existing code.
- Steps:
- Define an abstract class (
Device
). - Create specific device classes (
Light
,Fan
) inheriting from the abstract class. - Implement a factory class (
DeviceFactory
) to generate instances of these devices.
- Define an abstract class (
-
Adapter Pattern:
- Purpose: Makes incompatible interfaces compatible. Allows objects from different classes to work together.
- Steps:
- Define an adapter interface (
USPlug
). - Create adapter classes (
LightAdapter
,FanAdapter
) that implement this interface and adapt the devices (Light
,Fan
) to the required interface.
- Define an adapter interface (
Let’s move forward and start implementing these patterns.
Before diving into design patterns, we need to define the devices we'll be working with. Start by defining an abstract class Device
and the concrete device classes Light
and Fan
that inherit from Device
.
C#1// Abstract Product 2abstract class Device 3{ 4 public abstract void TurnOn(); 5 public abstract void TurnOff(); 6} 7 8// Concrete Product - Light 9class Light : Device 10{ 11 public override void TurnOn() => Console.WriteLine("Light is on."); 12 13 public override void TurnOff() => Console.WriteLine("Light is off."); 14} 15 16// Concrete Product - Fan 17class Fan : Device 18{ 19 private int speed; 20 21 public override void TurnOn() => Console.WriteLine("Fan is on."); 22 23 public override void TurnOff() => Console.WriteLine("Fan is off."); 24 25 public void SetSpeed(int speed) 26 { 27 this.speed = speed; 28 Console.WriteLine("Fan speed set to " + speed + "."); 29 } 30}
With our basic devices defined, we can now integrate the Factory Method pattern.
To begin with, we use the Factory Method pattern in C# to create an abstract class for our devices, derive specific device classes from this abstract class, and finally create a factory class responsible for generating instances of these device classes.
Let's break down the Factory Method pattern step by step.
Define an abstract factory class DeviceFactory
and the concrete factory classes LightFactory
and FanFactory
that create instances of Light
and Fan
.
C#1// Abstract Creator 2abstract class DeviceFactory 3{ 4 public abstract Device CreateDevice(); 5} 6 7// Concrete Creator - LightFactory 8class LightFactory : DeviceFactory 9{ 10 public override Device CreateDevice() => new Light(); 11} 12 13// Concrete Creator - FanFactory 14class FanFactory : DeviceFactory 15{ 16 public override Device CreateDevice() => new Fan(); 17}
Finally, integrate and test the Factory Method by creating instances of light and fan devices using the factory classes.
C#1// Main Program 2class Program 3{ 4 static void Main() 5 { 6 // Create a Light using the LightFactory 7 DeviceFactory lightFactory = new LightFactory(); 8 Device light = lightFactory.CreateDevice(); 9 light.TurnOn(); // Output: Light is on. 10 light.TurnOff(); // Output: Light is off. 11 12 // Create a Fan using the FanFactory 13 DeviceFactory fanFactory = new FanFactory(); 14 Device fan = fanFactory.CreateDevice(); 15 fan.TurnOn(); // Output: Fan is on. 16 ((Fan)fan).SetSpeed(3); // Output: Fan speed set to 3. 17 fan.TurnOff(); // Output: Fan is off. 18 } 19}
In this implementation, DeviceFactory
generates either a Light
or a Fan
device. The TurnOn
and TurnOff
methods are called on these devices to showcase their functionality.
Now, let's ensure our devices can interact with other parts of the system that expect a different interface. Specifically, we create an adapter to make our devices compatible with a method called Connect
.
Let's also break down the Adapter pattern step by step.
First, define an interface USPlug
and create adapter classes LightAdapter
and FanAdapter
that implement this interface to adapt the Light
and Fan
devices.
C#1// Adapter Pattern for Smart Home Devices 2interface USPlug 3{ 4 void Connect(); 5} 6 7// Adapter for Light 8class LightAdapter : USPlug 9{ 10 private Device light; 11 12 public LightAdapter(Device light) 13 { 14 this.light = light; 15 } 16 17 public void Connect() => light.TurnOn(); 18} 19 20// Adapter for Fan 21class FanAdapter : USPlug 22{ 23 private Device fan; 24 25 public FanAdapter(Device fan) 26 { 27 this.fan = fan; 28 } 29 30 public void Connect() => fan.TurnOn(); 31}
Finally, integrate and test the Adapter pattern by creating devices using the factory and adapting them to the USPlug
interface.
C#1// Main Program 2class Program 3{ 4 static void Main() 5 { 6 // Create a Light device using the LightFactory 7 DeviceFactory lightFactory = new LightFactory(); 8 Device light = lightFactory.CreateDevice(); 9 // Adapt the Light to the USPlug interface 10 USPlug lightAdapter = new LightAdapter(light); 11 lightAdapter.Connect(); // Output: Light is on. 12 13 // Create a Fan device using the FanFactory 14 DeviceFactory fanFactory = new FanFactory(); 15 Device fan = fanFactory.CreateDevice(); 16 // Adapt the Fan to the USPlug interface 17 USPlug fanAdapter = new FanAdapter(fan); 18 fanAdapter.Connect(); // Output: Fan is on. 19 } 20}
In this implementation, we use the DeviceFactory
to create instances of Light
and Fan
, then adapt these devices to the USPlug
interface using the LightAdapter
and FanAdapter
classes. The Connect
method is called on these adapters to showcase their functionality.
With these implementations, your smart home system will be more modular and flexible by using design patterns effectively. Happy coding!