DecoratorPattern | ||
DesignPatterns@71b1c6b531 | ||
FactoryPattern | ||
ObserverPattern | ||
ProxyPattern | ||
Singleton | ||
UML类图 | ||
.gitignore | ||
README.md |
DesignPatterns
1、单例模式
单例模式是属于创建型模式,提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。保证一个类只有一个实例,并提供一个访问它的全局访问点
- 单例类只能有一个实例
- 单例类必须自己创建自己的这一实例
- 单例类必须给所有其他对象提供这一实力
关键是:构造函数是私有的
主要解决:一个全局使用的类频繁的创建与销毁
优点:
- 内存中仅有一个实例,减小内存开销
- 避免资源的多重占用(写文件)
缺点:没有接口,不能继承,与单一职责原则冲突
实现:
-
懒汉式:
仅仅定义对象,在get函数里进行实例化
缺点就是线程不安全,解决办法就是:加锁 synchronized 保证单例;优点就是第一次调用才初始化避免了内存浪费
-
饿汉式
比较常用的方式,类加载时就初始化
缺点是浪费内存;优点是没有加锁,效率提高
-
双重校验锁
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
首先先判断该类是否有实例化,然后如果没有再加锁进行实例化。
-
登记式
最后采用的是饿汉式:
//TestSingleton.cs
class TestSingleton{
//设置名字
String name = null;
//创建实例并初始化
private static TestSingleton instance = new TestSingleton();
//构造函数
private TestSingleton(){}
//返回实例
public static TestSingleton getInstance(){
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//输出name
public void printInfo() {
Console.WriteLine("the name is " + name);
}
}
//SingletonMain.cs
class SingletonMain{
static void Main(string[] args){
//获得实例
TestSingleton test1 = TestSingleton.getInstance();
//设置姓名
test1.setName("Jack");
//获得实例
TestSingleton test2 = TestSingleton.getInstance();
test2.setName("Jane");
//输出名字
test1.printInfo();
test2.printInfo();
//判断是否为同一对象
if(test1 == test2){
Console.WriteLine("为同一个实例");
} else{
Console.WriteLine("Hello World!");
}
}
}
UML类图:
2、工厂模式
创建型模式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,而是通过共同的接口来指向新创建的对象。定义一个创建对象的接口,让其子类自己觉得实例化哪一个工厂类。
主要解决接口选择问题。
优点:调用者需要创建一个对象只需知道名称就可以了;扩展性高,如果想要增加一个产品,只需要扩展一个工厂类就可以;对于产品的具体实现对调用者来说是不可见的。
缺点:每次增加一个产品就需要增加一个具体的类和对象实现工厂,增加了复杂度和具体类的依赖。
注意:复杂对象适用于工厂模式,对于简单的对象只需要new就可以进行创建。
实现:创建一个Drinks的接口和实现Drinks接口的实体类,还需要定义工程类DrinksFactory
//Drinks接口
public interface Drinks
{
//定义饮料类型
string name { get; set; }
//定义方法
void make();
}
//实现Drinks的实体类
class Coffee : Drinks
{
public string name { get; set; }
public Coffee()
{
name = "coffee";
}
public void make()
{
Console.WriteLine("This is "+name);
}
}
class MilkTea :Drinks
{
public string name { get; set; }
public MilkTea()
{
name = "milk tea";
}
public void make()
{
Console.WriteLine("This is " + name);
}
}
//工厂类
class DrinksFactory
{
public Drinks getDrinks(String drinkType)
{
//判断是否为空
if (drinkType == null)
{
return null;
}
//根据输入的类型实例化对象
if (drinkType.Equals("COFFEE"))
{
return new Coffee();
}else if (drinkType.Equals("MILKTEA"))
{
return new MilkTea();
}
return null;
}
}
class FactoryPatternDemo
{
static void Main(string[] args)
{
DrinksFactory drinkShop = new DrinksFactory();
//获取咖啡对象
Drinks coffee = drinkShop.getDrinks("COFFEE");
coffee.make();
//获取奶茶对象
Drinks milkTea = drinkShop.getDrinks("MILKTEA");
milkTea.make();
}
}
UML类图:
3、抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
**优点:**当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
**缺点:**产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
我的理解:将上面的工厂模式,再抽象以下,有多个工厂生产不同的物品,每一个物品又有不同的类别。
4、代理模式
代理模式给某一个对象
提供一个代理对象,并由代理对象控制对原对象的引用。针对某些情况,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介作用。符合代码的开闭原则。
-
静态代理
- 创建服务类接口
- 实现服务接口
- 创建代理类
- 编写测试类
优点:可以做到在符合开闭原则的情况下对目标对象功能进行扩展
缺点:需要为每一个服务创建代理类,工作量太大
-
动态代理
Castle代理:
//抽象商店接口 public interface Shop { //购买饮料 void BuyDrinks(); }
//实现奶茶店类 class MilkTeaShop:Shop { public virtual void BuyDrinks() { Console.WriteLine("奶茶店收取费用"); } }
//中介类 public class ProxyShop:IInterceptor { public void Intercept(IInvocation invocation) { //执行奶茶店的逻辑 invocation.Proceed(); CollectIntermediaryFees(); } private void CollectIntermediaryFees() { Console.WriteLine("中介收取配送费!"); } }
class ByDrinksProxy { static void Main(string[] args) { Console.WriteLine("外卖中介帮你买奶茶"); Shop proxyShop = CreateShopProxy(); Console.WriteLine("中介成功出购买奶茶"); proxyShop.BuyDrinks(); } private static Shop CreateShopProxy() { ProxyGenerator proxyGenerator = new ProxyGenerator(); Shop proxyShop = proxyGenerator.CreateClassProxy<Shop>(new ProxyShop()); return proxyShop; } }
5、观察者模式
当对象存在着一对多的关系时,使用观察者模式。属于行为型模式,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
优点:观察者和被观察者是抽象耦合的,建立一套触发机制
缺点:通知所有观察者会花费很多时间;有可能存在循环依赖;观察者模式仅仅知道发生了变化,但是不知道如何发生变化。
实现:
//观察者的抽象类
abstract class Observer
{
//被观察者
protected Material material;
//更新价格
public abstract void update();
}
//实例化的两个观察类
class Product1 : Observer
{
public Product1(Material material){
this.material = material;
this.material.attach(this);
}
public override void update()
{
//计算商品价格
int price = 13 + this.material.getPrice();
Console.WriteLine("商品1价格更新为:"+price);
}
}
class Product2 : Observer
{
public Product2(Material material)
{
this.material = material;
this.material.attach(this);
}
public override void update()
{
//计算商品价格
int price = 18 + this.material.getPrice();
Console.WriteLine("商品2价格更新为:"+price);
}
}
//被观察着对象
class Material
{
//所有商店的集合
private List<Observer> shops = new List<Observer>();
private int price { get; set; }
//返回原材料的价格
public int getPrice()
{
return price;
}
//设置原材料的价格并更新商店的价格
public void setPrice(int price)
{
this.price = price;
this.updateAllPrice();
}
//增添观察者也就是商店
public void attach(Observer observer)
{
shops.Add(observer);
}
//更新价格
public void updateAllPrice()
{
foreach (Observer observer in shops)
{
observer.update();
}
}
}
class ObserverPatternDemo
{
static void Main(string[] args)
{
Material material = new Material();
new Product1(material);
new Product2(material);
Console.WriteLine("原材料价格改为15");
material.setPrice(15);
Console.WriteLine("原材料价格改为18");
material.setPrice(18);
}
}
UML:
6、装饰器模式
装饰器模式允许一个向现有的一个对象添加新的功能,同时不修改结构,属于结构型模式。动态的给一个对象添加一些额外的职责。
优点 :装饰类和被装饰类可以独立发展,不会耦合,动态的扩展一个实现类的功能
缺点:多层装饰比较复杂
实现:
//创建一个接口
public interface Product
{
//价格
int price { get; set; }
//名字
String name { get; set; }
void make();
}
//创建实现接口的被装饰类
class MilkGreenTea : Product
{
public int price { get ; set; }
public String name { get; set; }
public MilkGreenTea()
{
//初始化价格
price = 15;
name = "奶绿";
}
public void make()
{
Console.WriteLine(("你的产品为:" + name);
}
}
class MilkRedTea:Product
{
public int price { get; set; }
public String name { get; set; }
public MilkRedTea()
{
//初始化价格
price = 12;
name = "奶茶";
}
public void make()
{
Console.WriteLine("你的产品为:"+this.name);
}
}
//装饰类的抽象类
public abstract class Additives : Product
{
public int price { get ; set ; }
public String name { get; set; }
//被装饰的物品
protected Product product;
public Additives(Product product)
{
this.product = product;
}
public void make()
{
Console.WriteLine("你的产品为:" + this.name);
Console.WriteLine("你的价格:" + this.price);
}
}
//创建扩展的实体修饰类
class Pearl : Additives
{
public Pearl(Product product) : base(product)
{
this.name = this.product.name + "+" + "珍珠";
this.price = this.product.price + 5;
}
}
class Pudding : Additives
{
public Pudding(Product product) : base(product)
{
this.name = this.product.name + "+布丁" ;
this.price = this.product.price + 6;
}
}
class Program
{
static void Main(string[] args)
{
Additives drink1 = new Pudding(new Pearl(new MilkGreenTea()));
Additives drink2 = new Pudding(new Pearl(new MilkRedTea()));
Additives drink3 = new Pearl(new Pearl(new MilkRedTea()));
drink1.make();
drink2.make();
drink3.make();
}
}
UML图:
7、责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。JS 中的事件冒泡
优点:1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。