c#设计模式—-工厂方法模式

工厂方法模式是一种类创建型模式.在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类.

工厂方法模式包含以下4个角色:

(1)抽象产品:它是定义产品的接口.

(2)具体产品:它是实现抽象产品的接口的类.

(3)抽象工厂:在抽象工厂类或接口中声明了工厂方法,用于返回一个产品.抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口.

(4)具体工厂:它是抽象工厂类的子类.

以下为一个实例的演示代码:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
 interface Logger//抽象产品接口
 {
 void WriteLog();
 }
 class DatabaseLogger : Logger//数据库日志记录类
 {
 public void WriteLog()
 {
 Console.WriteLine("数据库日志记录");

}

 }
 class FileLogger : Logger//文件日志记录类
 {
 public void WriteLog()
 {
 Console.WriteLine("文件日志记录");

}

}

interface LoggerFactory//抽象工厂接口
 {

Logger CreateLogger();//抽象工厂方法

}
 class DatabaseLoggerFactory : LoggerFactory//数据库日志记录工厂类
 {
 public Logger CreateLogger()
 {
 Logger logger = new DatabaseLogger();

return logger;

}

 }
 class FileLoggerFactory : LoggerFactory//文件日志记录工厂类
 {

public Logger CreateLogger()
 {
 Logger logger = new FileLogger();

return logger;
 }

}
 class Program
{

 static void Main(string[] args)
 {
 LoggerFactory factory;//定义抽象工厂类对象引用;
 Logger logger;//定义产品抽象类对象引用;
 factory = new FileLoggerFactory();//创建文件日志记录工厂对象;
 logger = factory.CreateLogger();//创建文件日志记录对象
 logger.WriteLog();
 factory = new DatabaseLoggerFactory();//创建数据库日志记录工厂对象;
 logger = factory.CreateLogger();//创建数据库日志记录对象
 logger.WriteLog();
 Console.ReadKey();

}

 }
}

运行结果如下:

c#中的IEnumerable和IEnumerator

  • 之前一直不是很清楚IEnumerable和IEnumerator 具体区别 今天特地为此编写了一个自己 枚举类 继承自IEnumerable和IEnumerator 接口,我发现如果只继承IEnumerable而不继承IEnumerator 接口 是不可以实现foreach循环访问的因为使用foreach循环必须实现GetEumerator函数.IEnumerable是声明该类可以使用foreach循环访问,而IEnumerator是枚举器具体实现,也就是说 如果类继承了IEnumerable接口则表明此类对象是可以枚举的,具体怎么枚举则需要继承并实现IEnumerator接口.

public IEnumerator GetEnumerator()
{

return (IEnumerator)this;

}

另外我还发现,IEnumerator 接口的2个函数和一个属性 中 MoveNext()是自动调用执行的,Current是自动访问的,而且顺序是 使用foreach循环时首先执行MoveNext()函数把索引往后移一位,然后访问Current当前属性的值.所以当你继承这2个接口时索引定义要从 -1开始这样第一个访问的才能是数组索引为零的元素.

以下是我的实验代码和结果:


using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Collections;
 namespace test
 {
 struct point
 {
 public int x;
 public int y;
 public int z;
 }

class Myenum : IEnumerable, IEnumerator
 {
 private int index;
 private point[] points;

public Myenum(int numofpoint)
 {
 this.index = -1;
 points = new point[numofpoint];

for (int i = 0; i < points.Length; i++)
 {
 points[i].x = i;
 points[i].y = i * i;
 points[i].z = i * i * i;
 }
 }
 public IEnumerator GetEnumerator()
 {

return (IEnumerator)this;

}
 public object Current
 {
 get
 {
 Console.WriteLine("Current");
 return points[index];
 }
 }
 public bool MoveNext()
 {

index++;

if (index < points.Length&&index>=0)
 {
 Console.WriteLine("MoveNext()");
 return true;
 }
 else
 return false;

}
 public void Reset()
 {
 index = -1;
 Console.WriteLine("Reset()");
 }

}
 class Program
 {
 static void Main(string[] args)
 {

Myenum enum1 = new Myenum(5);

foreach (point p in enum1)
 {
 Console.WriteLine("(" + p.x.ToString() + "," + p.y.ToString() + "," + p.z.ToString() + ")");
 }

Console.Read();

}
 }
 }

c#基础学习

1.readonly 保护的是变量的位置不会在构造函数之外被改变.

2.c#的参数类型有4种:值参数,引用参数,输出参数和参数数组.

3.输出参数声明的修饰符是out,out参数是用ref参数加上元数据里的一个特殊属性.

4.参数数组允许向方法传递不定长的参数,声明它的修饰符是params,只有方法的最后一个参数才可以是参数数组,并且参数数组的类型必须是一维的数组.

5.在声明抽象方法时要加上abstract修饰符,并且只允许在同样被声明为abstract的类中声明抽象方法,所有非抽象的继承类都必须重写抽象方法.

6.如果构造函数的声明包含了static 修饰符,它就变成了一个静态的构造函数.

7.属性是字段的一种自然延伸,属性不代表存储的位置,它只是提供了访问的机制.

8.结构体是值类型,一个构造类型的变量之间存储了结构的数据,而一个类类型保存的是指向动态分配对象的引用.

考试

今天是9号了 11号要考试了,明天要开始复习了,对于我来说复习一门课程最多也就用一天时间足够了.因为考试对我来说真的很简单.哈哈

Unity3D之局域网CS对战(第六天笔记)

今天终于把全部的视频看完了,里面的代码也有基本理解了,也都全部敲了一遍,今天主要是游戏的结束逻辑我结束的界面设计.对我来说这个是挺简单的.

另外今天也把昨天的问题给解决了,昨天主要是人物的动画无法同步到其他客户端.最后发现是NetworkView这个组件只能同步单个组件或属性,

如果要同步多个属性只能再添加一个NetworkView组件然后把需要同步的属性赋值到Observed属性中,比如说你需要同步角色的位置信息那么你需要添加一个NetworkView然后再把角色的位置属性赋值到Observed属性,但是这个只能看到的是人物在移动并看不到动画在播放,因为人物的动画并没有同步到其他客户端,你需要再添加一个NetworkView组件然后把动画属性赋值到Observed.

但是如果属性多了的话这中方法就不适用了,那么还可以适用RPC进行同步如:

networkView.RPC(“PlayState”, RPCMode.All, “soldierFalling”);

把需要执行的动画都放到RPC上进行远程过程的调用.这样就可以把播放的动画同步到其他客户端了.

如果使用networkView组件那么直接执行: 如 animation.Play(animName);就可以了

 

今天调试了好久才发现这个问题.

 

 

Unity3D之局域网CS对战(第五天笔记)

今天主要学习了角色在局域网中的控制,怎样把角色同步到其他客户端然后各自控制自己的角色互不影响.使用RPC调用角色控制.

需要注意的是:

1. // go.GetComponent<Player>().SetOwnerPlayer(Network.player);//这个代码只设置了当前创建者中的战士的ownerPlayer属性在其他客户端这个属性是空的;

2. go.networkView.RPC(“SetOwnerPlayer”, RPCMode.AllBuffered, Network.player);//远程调用;使用这个远程调用

在 SetOwnerPlayer方法上面必须声明是[RPC];否则会出错.如下:

[RPC]//使用注解表示这个方法是一个远程调用;
public void SetOwnerPlayer(NetworkPlayer player)
{
this.ownerPlayer = player;
if (Network.player!=this.ownerPlayer)
{
LoseControl();

Debug.Log(“失去控制”);
}
}

3.需要同步的数据都需要使用RPC远程调用实现.

4.在需要获取同步角色中自身组件的函数中一定要把函数放在RPC远程调用函数中执行才有用这样执行的才是调用自身的那个.

如:需要在每个角色中获取

motor=this.GetComponent<CharacterMotor>();

则需要把motor=this.GetComponent<CharacterMotor>();放在 SetOwnerPlayer函数里面调用才行.

 

今天最终的效果还是没有调试出来,不知道是我的原因还是版本的原因,反正客户端和服务器端的动画还无法同步出来死亡伤害也无法实现,

只能明天再调试一下了.

Unity3D之局域网CS对战(第四天笔记)

今天又看了几集视频然后对着做了一遍,今天算是写的第二次笔记了,因为昨天没写所以只能一天写2篇了.

今天主要是场景的加载然后是对游戏角色的实例化局域网服务器和客户端的创建,还有游戏开始UI的设计.

需要注意的是以下几点.

1.在网络中需要用 Network.Instantiate(soldierPrefab, pos1.position, Quaternion.identity, group);实例化角色或物体.

2.创建UI的Alpha值可直接鼠标右键单击然后现在Tween进行添加然后对透明度进行调节.

3. OnConnectedToServer() 当客户端连接服务器成功的时候执行它.

4. Network.player//获取本地NetworkPlayer实例。  int group = int.Parse(player + “”);可以转换成组号.

5.GUITexture的图片需要再物体下添加相机组件然后在Game视图下才能看见.(编辑模式的时候),之前也因为这个调试了好久才发现没有在Game视图下看在Sence视图下是看不到的所以无法编辑.一直以为没有创建成功.

 

Unity3D之局域网CS对战(第三天笔记)

本来这篇笔记是应该在昨天写的但是因为昨天调试程序调试了很久没有成功,太晚了就没在写笔记了,改到现在进行补回.

昨天主要学习的是:

1.子弹射击的闪光效果(也就是枪火的效果),主要在Uuity3D中创建一个Quad然后给这个Quad指定一张贴图,把贴图背景设置为透明.

2.子弹射击的弹痕效果,方法和创建闪光效果类似但是另外需要添加法线贴图,需要2张图片.

3.子弹朝向问题,子弹的朝向是人物视野的中央而不是枪口的前方,然后再视野中央添加一个准星.

 

需要注意的问题:

1.之前一直调试都未成功后来才发现是在子弹的自带的碰撞器没有删除,本来在子弹中就已经用了射线碰撞器然后本身又有一个碰撞器 就导致物体一直处于碰撞状态.

2.然后就是给脚本的公共变量赋值时应该赋的是frefab而不是已经存在的物体,不然当物体消失是 变量的值也消失了.

3.Physics.Raycast(oriPos, direction, out hitinfo, length);此函数检测物体投射射线的碰撞,其中hitinfo是获取碰撞的信息.

//hitinfo.normal;//可以得到碰撞点的垂线向量 也就是碰撞面的法线.

//hitinfo.point是碰撞点.

Unity3D之局域网CS对战(第二天笔记)

今天学习了第一人称视野的控制和添加动画,原来实际上的动画就是控制骨骼的运动.所以当你挂载物体时如果要在动画中体现出来那么你就要挂载到相应的骨骼位置下,这样动画动起来你挂载的物体才能跟着动.比如说摄像机想要跟随头部的运动那么你就要挂载到相应的头部骨骼下才行.

学习中有以下几个重点:

1.

animation.Play(animName);//立即停止当前动画播放animName动画;
animation.CrossFade(animName, 0.2f);//有0.2秒的缓冲时间然后渐变为animName动画;

2.

LateUpdate是在所有Update函数调用后被调用。这可用于调整脚本执行顺序。例如:当物体在Update里移动时,跟随物体的相机可以在LateUpdate里实现。

之前看视频的时候发现视频里面siki老师讲的他是可以在当mouseLook脚本里面控制骨骼的旋转的,我自己放到我的项目里面发现确不行后面一节视频才讲到原来就是LateUpadate和Update先后调用问题,因为模型的动画是在每一帧都会调用的就相当于Update而对骨骼的旋转如果再放在Update里面就得不到相应的改变,只能放在LateUpate里面当动画执行后再去执行鼠标对模型骨骼的旋转.

3.

float h=Input.GetAxis(“Horizontal”);//获取键盘的左右方向输入;
float v=Input.GetAxis(“Vertical”);//获取键盘的上下方向输入;

 

 

Unity3D之局域网CS对战(第一天笔记)

今天准备开始学习一下Unity3D网络游戏的开发了,刚好在泰克在线上看到了这个CS的局域网对战项目,正好符合我的口味,准备一天看个一章应该没问题关键是总共才3章估计3天也就看完了也跟着做完了哈哈.

今天主要了解了以下几点:

1.Unity3D的网络组件—-network,它实际上是一个类

Network类是网络实现的核心并提供核心函数。

2.利用 Network.InitializeServer进行初始化一个服务器,它需要3个参数,最大连接数,端口号,是否NAT地址转换.

3.给需要同步的物体加上 network view组件,此组件用来在局域网之内去同步一个游戏物体的组件,但是它会把创建他的作为它的主人,同步到其他客户端,它自己本身不会被其他客户端同步.

4.客户端连接使用Network.Connect(ip, listenPort);其中IP则是IP地址,而listenPort则是服务器端创建的端口号.

5.第一称里面的Mouse Look.cs脚本是鼠标控制角色的视角的脚本,而其他的脚本是控制角色的移动的.

6.Input.GetAxis(“Mouse X”)可以获取鼠标或键盘的输入然后对角色进行控制,

如.Input.GetAxis(“Mouse X”)就是获取鼠标左右方向的移动,而 Input.GetAxis(“Horizontal”);是获取键盘左右方向的移动.