今天看到了两篇博文《关于一道C#上机题的一点想法》和《关于 》,都是说约瑟夫环的OO实现,这两篇文章给了我很好的启发,但是二者的实现和我相像的还有一些差距,于是忍不住自己动了下手。
今天看到了两篇博文《关于一道C#上机题的一点想法》和《关于<关于一道C#上机题的一点想法> 》,都是说约瑟夫环的OO实现,这两篇文章给了我很好的启发,但是二者的实现和我相像的还有一些差距,于是忍不住自己动了下手。
既然是OO,那肯定要符合OO的原则,最先想到的就是开放封闭原则。对于约瑟夫环哪些是可变的,哪些是不可变的,我思考了一下。
可变的部分:
1、环的长度和起始的位置(这个是最基本的扩展);
2、找到下一个人位置的方式(可以隔三个,也可以隔五个,甚至可以进三个退两个);
3、找到人后所做的操作(简单地输出或是让他跳三跳、给朵大红花);
4、围成圈的不一定是人,阿猫阿狗也可以。
不变的部分:
1、环是肯定不会变的;
2、肯定有一个确定下一个位置的方式;
3、找到人后无论给不给他红花,但他一定要出列,不然游戏玩不完了。
基于以上分析,将不变的部分写了个抽象泛型基类。之所以用抽象,就因为很多变化的东西不能确定;之所以用泛型,就是给阿猫阿狗准备的。
基类
public abstract class JosephusRing<T>
{
private int currentPosition;
protected List<T> ring;
public JosephusRing(int length, int startPosition)
{
CreateRing(length); //将环的构造放到子类来完成,应该算是工厂方法模式吧。
this.currentPosition = startPosition;
}
public void NextStep()
{
currentPosition = Next(currentPosition);
Process(currentPosition);
ring.RemoveAt(currentPosition); //出列是不变的
}
public void RunToEnd()
{
while (ring.Count > 0)
{
NextStep();
}
}
protected abstract int Next(int current); //肯定有方法找到下一个位置,但是怎么找不确定
protected abstract void Process(int current); //找到后要进行一些处理,至于是跳三跳还是戴红花那就不知道了
protected abstract void CreateRing(int length);
}
基类实现了约瑟夫环的最核心操作,接下来的派生就可以按需求来定制。
派生类
public class JosephusRingInt32 : JosephusRing<int>
{
public JosephusRingInt32(int length, int startPosition)
: base(length, startPosition)
{
}
protected override int Next(int current) //从1数到3
{
return (current + 2) % base.ring.Count;
}
protected override void Process(int current) //只是简单地输出
{
Console.WriteLine(base.ring[current].ToString());
}
//构造环的过程只能放到派生类来完成,如果是一圈阿猫,或许你就得给它们依次起个名字
protected override void CreateRing(int length)
{
int[] r = new int[length];
for (int i = 0; i < length; ++i)
r[i] = i + 1;
base.ring = new List<int>(r);
}
}
这个派生类完成了最简单、最传统的操作,当然可以扩展得复杂一些。接下来按要求执行就可以了。
执行
class Program
{
static public void Main()
{
JosephusRingInt32 aRing = new JosephusRingInt32(17, 0);
aRing.RunToEnd();
}
}
结果就不截图了,和《关于<关于一道C#上机题的一点想法> 》一文相同。
以上纯属一己之见,也许对开放封闭原则领会的不是很好,还恳请高手指点。