这个模式有三个对象:工厂、用户、产品;这么说可能还有点抽象,说具体点,就是当我们在代码中需要生成一个类实例时,不直接去拿到这个类名,然后new;而是通过一个工厂类(例如EntityFactory),给该工厂类传要创建的类名的字符串,获取到最后生成的类实例;这样做的好处是,将对象的构造和使用隔离,使之模块化,工厂化。
C#示例代码如下所示:
//设计模式----工厂模式示例代码
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
abstract class Animal
{
public string name;
public Animal(string _name) { name = _name; }
abstract public void Func() ;
}
class Dog: Animal
{
public Dog(string _name) :base(_name) { name = _name; }
override public void Func()
{
Console.WriteLine($"Dog, name is {name}");
}
}
class Monkey:Animal
{
public Monkey(string _name) : base(_name) { name = _name; }
override public void Func()
{
Console.WriteLine($"Monkey, name is {name}");
}
}
class Duck:Animal
{
public Duck(string _name) : base(_name) { name = _name; }
override public void Func()
{
Console.WriteLine($"Duck, name is {name}");
}
}
class AnimalFactory // 只需要传字符串到工厂,就能生成对应的类实例,然后利用多态,调用一样的接口,对应不一样的实现
{
private static AnimalFactory Instance;
public static AnimalFactory GetInstance()
{
if(Instance == null)
{
Instance = new AnimalFactory();
}
return Instance;
}
public dynamic CreateAnimal(string class_name, string animal_name)
{
Type type = Type.GetType("ConsoleApp1." + class_name); // 利用反射获取到对应类名的Type
dynamic obj = Activator.CreateInstance(type, new object[] { animal_name}); //生成对应的实例
return obj;
}
}
class Program
{
public static void Main()
{
Dictionary<string, string> nameDic = new Dictionary<string, string>
{
{ "Dog", "xiaowang" },
{ "Duck", "xiaoli" },
{ "Monkey", "xiaozhang" },
};
foreach(var namePair in nameDic)
{
Animal animal = (Animal)AnimalFactory.GetInstance().CreateAnimal(namePair.Key, namePair.Value);
animal?.Func();
}
}
}
}
在内存中只存在一个实例对象,通常的构成是:私有构造函数、静态公共获取函数、私有静态自身成员;创建单例的方式有懒汉模式、饿汉模式、静态内部类实现等。
这是C++实现
#include
#include
using namespace std;
class Singleton1 // 懒汉模式
{
private:
static Singleton1* _instance;
Singleton1() { cout << "Singleton1 created !!!!"; }
public:
static Singleton1* GetInstance()
{
if (_instance == NULL)
{
_instance = new Singleton1();
}
return _instance;
}
};
Singleton1* Singleton1::_instance;
//--------------------------------------------------------------------------
class Singleton2 // 饿汉模式
{
private:
static Singleton2* _instance;
Singleton2() {cout<<"Singleton2 created !!!!"; };
public:
static Singleton2* GetInstance()
{
return _instance;
}
};
Singleton2* Singleton2::_instance = new Singleton2();
//------------------------------------------------------------------------------------
class Singleton3 // 局部静态变量实现,还有一种是加锁模式,比较麻烦且耗,需要的百度下就行
{
private:
Singleton3() { cout << "Singleton3 created !!!!"; };
public:
static Singleton3& GetInstance()
{
static Singleton3 instance;
return instance;
}
};
这是c#实现
// 设计模式————单例模式(懒汉、饿汉、静态内部类实现)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
public class Singleton1 // 懒汉模式, 多线程不安全,会创建多个
{
private static Singleton1 _Singleton1 = null;
private Singleton1()
{
Console.WriteLine("Singleton1被构造");
}
public static Singleton1 GetInstance()
{
if (_Singleton1 == null)
{
_Singleton1 = new Singleton1();
}
return _Singleton1;
}
}
public class Singleton2 // 饿汉模式,这里多线程运行状态下是线程安全的
{
private Singleton2() { Console.WriteLine("Singleton2被构造"); }
private static Singleton2 Instance = new Singleton2();
public static Singleton2 GetInstance()
{
return Instance;
}
}
public class Singleton3 // 内部静态类实现,多线程安全
{
private Singleton3() { Console.WriteLine("Singleton3被构造"); }
private static class InnerClass
{
internal static Singleton3 instance = new Singleton3();
static InnerClass() {} //静态构造函数
}
public static Singleton3 GetInstance()
{
return InnerClass.instance;
}
}
public class Singleton4 //静态构造函数, 构造线程安全,保证内存只有一个这个实例对象
{
private static Singleton4 Instance;
private Singleton4() { Console.WriteLine("Singleton4被构造"); }
static Singleton4()
{
Instance = new Singleton4();
}
public static Singleton4 GetInstance()
{
return Instance;
}
}
public class Singleton5 // 惰性构造,构造线程安全
{
private static readonly Singleton5 instance = new Singleton5();
private Singleton5() { Console.WriteLine("Singleton5被构造"); }
static Singleton5() {} // 静态构造,保证只调用一次,并且在调用一个静态方法或者属性时,初始化这个类
public static Singleton5 Instance
{
get
{
return instance;
}
}
}
class Program
{
public static void F1()
{
for (int i = 0; i < 10; ++i)
{
var a = Singleton2.GetInstance();
}
}
public static void Main()
{
// 验证多线程状态下的线程安全
Thread thread1 = new Thread(new ThreadStart(F1));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(F1));
thread2.Start();
}
}
}
当一个事件发生时,需要去通知其他订阅者;例如游戏里面常见的领完奖励之后刷新UI界面等等。通过注册的方式,实现事件的统一下触发以及代码的隔离。
c#代码示例
//设计模式----观察者/订阅者模式
using System;
namespace ConsoleApp1
{
public class Subscriber // 发布者
{
public event Action mineActions;
public Subscriber()
{
}
public void registEvent(Action action)
{
mineActions += action;
}
public void unRegisterEvent(Action action)
{
mineActions -= action;
}
public void publishEvent()
{
mineActions?.Invoke();
}
}
public abstract class ObserverBase
{
public string name;
public ObserverBase(string _name)
{
name = _name;
}
public abstract void F1();
}
public class ObserverA: ObserverBase // 订阅者A
{
public ObserverA(string _name):base(_name)
{
name = _name;
}
public override void F1()
{
Console.WriteLine($"this is {name} print !!!!!!!");
}
}
public class ObserverB: ObserverBase // 订阅者B
{
public ObserverB(string _name) : base(_name)
{
name = _name;
}
public override void F1()
{
Console.WriteLine($"this is {name} print !!!!!!!");
}
}
public class ObserverC : ObserverBase // 订阅者C
{
public ObserverC(string _name) : base(_name)
{
name = _name;
}
public override void F1()
{
Console.WriteLine($"this is {name} print !!!!!!!");
}
}
class Program
{
public static void Main()
{
Subscriber subscriber = new Subscriber();
ObserverA observerA = new ObserverA("ObserverA");
ObserverB observerB = new ObserverB("ObserverB");
ObserverC observerC = new ObserverC("ObserverC");
//订阅
subscriber.registEvent(observerA.F1);
subscriber.registEvent(observerB.F1);
subscriber.registEvent(observerC.F1);
//发布事件
subscriber.publishEvent();
//取消订阅
subscriber.unRegisterEvent(observerA.F1);
subscriber.unRegisterEvent(observerB.F1);
subscriber.unRegisterEvent(observerC.F1);
}
}
}
意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决: 在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
同一种方式有多重实现方法,例如
代码示例
using System;
using System.Collections.Generic;
using System.Text;
namespace Strategy
{
public abstract class StrategyBase
{
public abstract int F(int a, int b);
}
public class StrategyA: StrategyBase // 策略A
{
public override int F(int a, int b)
{
return a + b;
}
}
public class StrategyB : StrategyBase // 策略B
{
public override int F(int a, int b)
{
return a - b;
}
}
public class StrategyC : StrategyBase // 策略C
{
public override int F(int a, int b)
{
return a * b;
}
}
public class Context // 代表上下文
{
StrategyBase strategyBase;
public Context(StrategyBase _strategy)
{
strategyBase = _strategy;
}
public int F(int a, int b)
{
return strategyBase.F(a, b);
}
}
public class Program
{
public static void Main()
{
Context a = new Context(new StrategyA()); // 使用策略A
Context b = new Context(new StrategyB()); // 使用策略B
Context c = new Context(new StrategyC()); // 使用策略C
//调用的时候使用统一接口 F
Console.WriteLine($"a.F(1,2) = {a.F(1, 2)}, b.F(1, 2) = {b.F(1, 2)}, c.F(1, 2) = {c.F(1, 2)}");
}
}
}
在上述的示例代码中,对于同样的使用环境(Context类),当使用不一样的策略是,可以有不一样的实现。
在真实的某个对象上再包一层代码,可以很方便的扩展其功能;例如游戏中的相机,我们可以在原生相机的基础上包装一层,然后可以在这一层代理里面加一些保护、实现一些原生接口函数的组合功能等。
动机:限制对目标对象的直接访问,降低耦合度;还可以实现一些真实对象没有的接口或者一些现有功能的组合。
示例代码:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp1
{
class Subject // 真实对象
{
public void fun1()
{
}
public void fun2()
{
}
public void fun3()
{
}
}
class SubjectProxy //代理对象,实现和真实对象一样的接口,可以限制对目标对象的直接访问,降低耦合度。
{
Subject subject;
public SubjectProxy(Subject _subject)
{
subject = _subject;
}
public void fun1() // 这里做封装,可以打log,加保护
{
subject.fun1();
}
public void fun2()
{
subject.fun2();
}
public void fun3()
{
subject.fun3();
}
}
public class Proxy
{
public static void Main()
{
SubjectProxy subjectProxy = new SubjectProxy(new Subject());
subjectProxy.fun1();
subjectProxy.fun2();
subjectProxy.fun3();
}
}
}
可以对原来的函数或者类进行扩展;对于类的装饰,可以实现组件式的代码结构,使得各个功能可以和方便的添加与删除,并且代码的逻辑也会很清晰;实现的功能是以组件的形式实现与继承相似的效果。
解决的问题: 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp1
{
public abstract class Shape // 抽象基类
{
public abstract void Print();
}
public class Circle: Shape // 圆形
{
public override void Print()
{
Console.WriteLine("This is Circle Draw !!");
}
}
public class Triangle : Shape // 三角形
{
public override void Print()
{
Console.WriteLine("This is Triangle Draw !!");
}
}
public class Decorator: Shape // 装饰类
{
public Shape shape;
public Decorator(Shape _shape)
{
shape = _shape;
}
public override void Print()
{
Console.WriteLine("This is Triangle Draw !!");
}
}
public class ColorShapeDecorator : Decorator // 装饰类型1
{
public ColorShapeDecorator(Shape _Shape) : base(_Shape)
{
}
public override void Print()
{
shape.Print();
}
public void Color() //相当于在传进来Shape的基础上,增加了Color接口
{
// DoSomething
Console.WriteLine("This is Color function !!");
}
}
public class GeometryShapeDecorator : Decorator // 装饰类型2
{
public GeometryShapeDecorator(Shape _Shape) : base(_Shape)
{
}
public override void Print()
{
shape.Print();
}
public void GetArea() //相当于在传进来Shape的基础上,增加了GetArea接口
{
// DoSomething
Console.WriteLine("this is GetArea function !!");
}
public void GetGirth() //相当于在传进来Shape的基础上,增加了GetGirth接口
{
// DoSomething
Console.WriteLine("this is GetGirth function !!");
}
}
class DecoratorTest
{
public static void Main()
{
Circle circle = new Circle();
circle.Print();
Console.WriteLine("--------------------------------------------");
Triangle triangle = new Triangle();
triangle.Print();
Console.WriteLine("--------------------------------------------");
ColorShapeDecorator ShapeDecoratorShape1 = new ColorShapeDecorator(circle);
ShapeDecoratorShape1.Print();
ShapeDecoratorShape1.Color(); // 在circle的基础上扩展了Color函数
Console.WriteLine("--------------------------------------------");
GeometryShapeDecorator ShapeDecoratorShape2 = new GeometryShapeDecorator(triangle);
ShapeDecoratorShape2.Print();
ShapeDecoratorShape2.GetArea(); // 在triangle的基础上扩展了GetArea、GetGirth等函数
Console.WriteLine("--------------------------------------------");
}
}
}