C# 设计模式·创建型模式
面试问到这个··答不出来就是没有架构能力···这里学习一下···面试的时候直接让我说出26种设计模式··当时就懵逼了··我记得好像之前看的时候是23种的 还有3个是啥的···
这里先列出几种创建型模式,工厂、抽象工厂、单例,建造者、原型,后续在更新
工厂模式:缺点是每增加一个类型就得增加一个工具类和对象工厂类(反射可以避免修改这个···)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; namespace ExercisePrj.Dsignmode { public class ShapeFactory { public static IShape CtreateShape(string shape) { if (shape == "Line") { return new Line(); } else if (shape == "Circle") { return new Circle(); } return null; }
//反射的实现方式,规定一个统一的类命名方式,通过反射初始化 public static IShape CtreateWithReflection(string shape) { Assembly assembly = Assembly.GetExecutingAssembly(); var ishape = assembly.CreateInstance("ExercisePrj.Dsignmode."+shape); return ishape as IShape; } } public interface IShape { void Draw(); } public class Line: IShape { public void Draw()//隐式封闭实现,子类可以隐藏不能重写,类调用会执行这个 { Console.WriteLine("draw line"); } void IShape.Draw()//显示实现,接口调用会执行这个 { Console.WriteLine("IShape.DrawLine"); } } public class Circle:IShape { public void Draw() { Console.WriteLine("draw Circle"); } } }
抽象工厂模式,简单讲就是比上边更流弊的工厂模式···这里有用到上边的类型
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExercisePrj.Dsignmode { //抽象工厂类 public abstract class AbstractFactory { public abstract IShape GetShape(string shape); public abstract IColor GetColor(string color); } //工厂类子类 public class ShapeFactoryEx:AbstractFactory { public override IShape GetShape(string shape) { return ShapeFactory.CtreateShape(shape);//偷个懒 } public override IColor GetColor(string color) { return null; } } public class ColorFactory : AbstractFactory { public override IShape GetShape(string shape) { return null; } public override IColor GetColor(string color) { if(color=="blue") { return new Blue(); } else if (color=="red") { return new Red(); } return null; } } //工厂创造器 public class FactoryProducer { public static AbstractFactory getFactory( string SType) { if(SType=="shape") { return new ShapeFactoryEx(); } else if(SType=="color") { return new ColorFactory(); } return null; } } public interface IColor { void Fill(); } public class Blue:IColor { public void Fill() { Console.WriteLine("Blue"); } } public class Red : IColor { public void Fill() { Console.WriteLine("Red"); } } }
单例模式:平时用的时候连锁都没加···上次面试的时候,人家问在多线程里边会出啥问题···当时就没反应过来·,说这有啥问题的·都是一个对象调方法就是··完事才想起来,如果初始化的函数在多线程里边就是线程不安全了··简直蒙蔽··这里列好几种写法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExercisePrj.Dsignmode { public class Singleton { private Singleton() { } //private static Singleton m_Singleton; //private static readonly object lockvalue = new object(); //public static Singleton GetInstance() //{ // //return m_Singleton ?? new Singleton();//不加锁 线程不安全 // if (m_Singleton == null) // { // lock (lockvalue)//枷锁//这里还可以加双锁,就是在里边判断是不是空 // { // return new Singleton(); // } // } // return m_Singleton; //} public static readonly Singleton Instance = new Singleton();//据说这个是最流弊的写法··跟下边的写法是一个意思·· //public static readonly Singleton Instance=null //static Singleton() //{ // Instance = new Singleton(); //} } }
建造者模式,将一个复杂的构造与其表示分开,使用同样的构建创建不同的表示··感觉就是做了可变动的组合,然后用一个类去构造这个变动组合类,一边排列组型或者菜单之类的应用场景都适合
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExercisePrj.Dsignmode { //构建类 public class MealBuilder { public Meal prepareVegMeal() { Meal meal = new Meal(); meal.addItem(new VegBurger()); meal.addItem(new Coke()); return meal; } public Meal prepareNonVegMeal() { Meal meal = new Meal(); meal.addItem(new ChickenBurger()); meal.addItem(new Pepsi()); return meal; } } //实体接口 public interface Item { string name { get;} float price { get; } IPacking packing(); } //实体关联接口 public interface IPacking { string pack(); } //不同实体 public class Wrapper:IPacking { public string pack() { return "Wrapper"; } } public class Bottle:IPacking { public string pack() { return "Bottle"; } } public abstract class Burger:Item { public IPacking packing() { return new Wrapper(); } public abstract string name { get; } public abstract float price { get; } } public abstract class ColdDrink:Item { public IPacking packing() { return new Bottle(); } public abstract string name { get; } public abstract float price { get; } } public class VegBurger:Burger { public override string name { get; } public override float price { get; } public VegBurger() { name = "Veg Burger"; price = 25.0f; } } public class ChickenBurger: Burger { public override string name { get; } public override float price { get; } public ChickenBurger() { name = "Chicken Burger"; price = 50.0f; } } public class Coke : ColdDrink { public override string name { get; } public override float price { get; } public Coke() { name = "Coke"; price = 30.0f; } } public class Pepsi : ColdDrink { public override string name { get; } public override float price { get; } public Pepsi() { name = "Pepsi"; price = 35.0f; } } //不同的组合类 public class Meal { private List<Item> Items = new List<Item>(); public void addItem(Item item) { Items.Add(item); } public float getCost() { float cost = 0; foreach(var item in Items) { cost += item.price; } return cost; } public void ShowItems() { foreach(var item in Items) { Console.WriteLine("name={0},packing={1},price={2}", item.name, item.packing().pack(), item.price); } } } }
原型模式,就是克隆··是为了避免创建新对象,采用克隆的方式··,讲道理一般实现的克隆是直接new对象然后赋值,这也没法避免啊···,网上写的好多实现方式都是浅复制,这玩意浅复制能行么,如果对象里边的属性或者字段都是基元类型,这无所谓修改的时候就相当于直接指定新的引用对象·,如果不是·哪克隆出来的所有对象里边的引用类型都得单独new,不然可能都得指向一个对象了,·····python有deepcopy, C#好像没有这个····这里是在网上查的用序列化和反序列的方式实现深复制,这样不用new对象···得注意克隆方式
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading.Tasks; namespace ExercisePrj.Dsignmode { // public class ApplianceCach { private static Dictionary<string, Appliance> ApplianceMap = new Dictionary<string, Appliance>(); public static Appliance GetApplicance(string shapeId) { Appliance cachAppliance = ApplianceMap[shapeId]; return (Appliance)cachAppliance.Clone(); } public static void loadCache() { Fridge fridge = new Fridge(); fridge.ID = "1"; ApplianceMap.Add(fridge.ID, fridge); Television tv = new Television(); tv.ID = "2"; ApplianceMap.Add(tv.ID, tv); } } [Serializable] public abstract class Appliance:ICloneable { protected string type; private string id; public string Type { get { return type; } } public string ID { get { return id; } set { id = value; } } public abstract void DoWork(); public object Clone() { object obj = null; //将对象序列化成内存中的二进制流 BinaryFormatter inputFormatter = new BinaryFormatter(); MemoryStream inputStream; using (inputStream = new MemoryStream()) { inputFormatter.Serialize(inputStream, this); } //将二进制流反序列化为对象 using (MemoryStream outputStream = new MemoryStream(inputStream.ToArray())) { BinaryFormatter outputFormatter = new BinaryFormatter(); obj = outputFormatter.Deserialize(outputStream); } return obj; } } public class Fridge :Appliance { public Fridge() { type = "Fridge"; } public override void DoWork() { Console.WriteLine("do some fridge job"); } } public class Television:Appliance { public Television() { type = "Television"; } public override void DoWork() { Console.WriteLine("do some Television job"); } } }