Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 私有成员访问的设计模式?_C#_Oop - Fatal编程技术网

C# 私有成员访问的设计模式?

C# 私有成员访问的设计模式?,c#,oop,C#,Oop,让我们用这个简单的例子: Connect4Board.cs: public class Connect4Board { private Box[,] _boxes = new Box[7, 6]; public void DropPieceAt(int column, bool redPiece) { //Safe modifications to box colors. } public Box GetBoxAt(in

让我们用这个简单的例子:

Connect4Board.cs:

public class Connect4Board
{
    private Box[,] _boxes = new Box[7, 6];

    public void DropPieceAt(int column, bool redPiece)
    {
        //Safe modifications to box colors.
    }        

    public Box GetBoxAt(int x, int y)
    {
        return _boxes[x, y];
    }
}
Box.cs

public class Box
{
    public bool IsRed { get; private set; }
    public bool IsEmpty { get; private set; }
}
我希望
GetBoxAt()
返回具有只读属性的框。但是,我希望我的
Connect4Board
能够更改框的颜色

假设我根本不想使用
internal
修饰符

我的解决方案(相当难看):

公共类连接板
{
private Box.MutableBox[,]u MutableBox=new Box.MutableBox[7,6];
公共连接板()
{
对于(int y=0;y<6;y++)
{
对于(int x=0;x<7;x++)
{
_MutableBox[x,y]=新的Box.MutableBox();
}
}
}
公共void DropPieceAt(int列,bool isRed)
{
//安全修改框颜色。
}        
公用箱GetBoxAt(整数x,整数y)
{
返回_mutablebox[x,y].Box;
}
}
公共类箱
{
公共bool IsRed{get;private set;}
公共布尔是空的{get;私有集;}
私人信箱()
{
}
公共类可变框
{
公共框{get;private set;}
公共可变框()
{
Box=新Box();
}
public void MakeRed(){//I can modify Box here}
public void MakeYellow(){//I can modify Box here}
public void MakeEmpty(){//I can modify Box here}
}
}
有没有一种好的设计模式可以让它更优雅?

这对你有用吗? 使用静态工厂使长方体不可变,并添加返回具有各种颜色的新长方体的静态属性

  public class Box
  {
       private Box() {}
       private Box(Color color) { Color = color; }
       public static Box Make(Color color) { return new Box(color); }
       public static Box RedBox { get { return new Box(Color.Red); } }
       public static Box GreenBox { get { return new Box(Color.Green); } }
       public static Box BlueBox { get { return new Box(Color.Blue); } }
       //   ... etc.
   }

解决方案1

您可以在
周围创建一个不可变的包装器
Connect4Board
将在内部使用
MutableBox
类,但将
ImmutableBox
公开给消费者

public interface IBox
{
    bool IsRed { get; }
    bool IsEmpty { get; }
}

public class MutableBox : IBox
{
    public bool IsRed { get; set; }
    public bool IsEmpty {get; set; }
    public IBox MakeImmutable()
    {
        return new ImmutableBox(this);
    }
}

public class ImmutableBox : IBox 
{
    private IBox innerBox;
    public ImmutableBox(IBox innerBox) { this.innerBox = innerBox; }
    public bool IsRed { get { return innerBox.IsRed; } }
    public bool IsEmpty { get { return innerBox.IsEmpty; } }
}

public class Connect4Board
{
    private MutableBox[,] boxes = new MutableBox[7, 6];

    public void DropPieceAt(int column, bool redPiece)
    {
        // perform modifications
    }

    public IBox GetBoxAt(int x, int y)
    {
        return boxes[x,y].MakeImmutable();
    }
}
解决方案2

你可以用它来达到这个目的吗? 创建一个接口
IMutableBox

public interface IMutableBox
{
    void SetIsRed(bool isRed);

    void SetIsEmpty(bool isEmpty);
}

public class Box : IMutableBox
{
    private bool isRed;
    private bool isEmpty;

    public bool IsRed { get { return isRed; } }
    public bool IsEmpty { get { return isEmpty; } }

    void IMutableBox.SetIsRed(bool isRed)
    {
        this.isRed = isRed;
    }

    void IMutableBox.SetIsEmpty(bool isEmpty)
    {
        this.isEmpty = isEmpty;
    }
}
var box = new Box();
var mutableBox = box as IMutableBox;
mutableBox.SetEmpty(true);
现在,为了变异
Box
,您需要将其强制转换为
IMutableBox

public interface IMutableBox
{
    void SetIsRed(bool isRed);

    void SetIsEmpty(bool isEmpty);
}

public class Box : IMutableBox
{
    private bool isRed;
    private bool isEmpty;

    public bool IsRed { get { return isRed; } }
    public bool IsEmpty { get { return isEmpty; } }

    void IMutableBox.SetIsRed(bool isRed)
    {
        this.isRed = isRed;
    }

    void IMutableBox.SetIsEmpty(bool isEmpty)
    {
        this.isEmpty = isEmpty;
    }
}
var box = new Box();
var mutableBox = box as IMutableBox;
mutableBox.SetEmpty(true);

你可以使用很多策略

编程到接口通常很有用。下面的IBox界面不允许人们编辑该框(不将其转换为
),但仍然使代码保持简单

public class Connect4Board
{
    private Box[,] _boxes = new Box[7, 6];

    public void DropPieceAt(int column, bool redPiece)
    {
        //Safe modifications to box colors.
    }        

    public IBox GetBoxAt(int x, int y)
    {
        return _boxes[x, y];
    }
}

public interface IBox
{
    bool IsRed { get; }
    bool IsEmpty { get; }
}

public class Box : IBox
{
    public bool IsRed { get; set; }
    public bool IsEmpty { get; set; }
}
另一种方法是使长方体始终不可变(如字符串),而不是修改长方体的状态,只需修改哪个长方体位于数组中的哪个位置:

public class Connect4Board
{
    private Box[,] _boxes = new Box[7, 6];

    public Connect4Board()
    {
        for(int i = 0; i<7; i++)
        {
            for(int j = 0; j<6; j++)
            {
                // Notice how you're not changing a color, but assigning the location
                _boxes[i,j] = Box.Empty;
            }
        }
    }

    public void DropPieceAt(int column, bool redPiece)
    {
        // Modifications to the top empty location in the given column.
    }        

    public Box GetBoxAt(int x, int y)
    {
        return _boxes[x, y];
    }
}

public class Box
{
    public bool IsRed { get; private set; }
    public bool IsBlack { get; private set; }
    public bool IsEmpty { get; private set; }

    private Box() {}

    public static readonly Box Red = new Box{IsRed = true};
    public static readonly Box Black = new Box{IsBlack = true};
    public static readonly Box Empty = new Box{IsEmpty = true};
}
公共类连接板
{
专用盒子[,]u盒子=新盒子[7,6];
公共连接板()
{

对于(int i=0;i您可以制作一个
ReadOnlyBox
,它可以作为您的
框的外观
,非常类似于
ReadOnlyCollection

[Flags]
public enum BoxState
{
    Empty = 0,
    Red = 1 << 0,
    Black = 1 << 1
}

[Flags]
public enum BoardColor
{
    Red = 1 << 0,
    Black = 1 << 1
}

public interface IBox
{
    BoxState State { get; }
}

public class Box : IBox
{
    public BoxState State { get; set; }
}

public class ReadOnlyBox : IBox
{
    private readonly IBox _box;

    public ReadOnlyBox(IBox box)
    {
        _box = box;
    }

    public BoxState State { get { return _box.State; } }
}

public class Connect4Board
{
    private const int _boardWidth = 7;
    private const int _boardHeight = 6;
    private Box[,] _boxes = new Box[_boardWidth, _boardHeight];

    public void DropPieceAt(int column, BoardColor color)
    {
        for(int height = 0; height < _boardHeight; height++)
        {
            if(_boxes[column, height].State != BoxState.Empty) continue;

            _boxes[column, height].State = (BoxState)color;
            break;
        }
    }        

    public IBox GetBoxAt(int x, int y)
    {
        return new ReadOnlyBox(_boxes[x, y]);
    }
}
[标志]
公共枚举状态
{
空=0,

Red=1一个选项是不将整个
对象返回给用户,而是只让他们查询正方形的状态。此外,您可以不使用IsEmpty/IsRed,只为正方形的状态创建一个
enum
enum SquareState{Empty,Black,Red}
)最后,您可以创建一个
IBox
接口(它是公共的),然后创建
Box
一个
ConnectBoard
的嵌套类(它实现了
IBox
)。然后,您可以让您的查询方法向用户返回一个
IBox
。@dlev应该作为答案发布。如果您希望
Connect4Board
能够更改
框的颜色,那么
框不是不可变的。如果
Connect4Board`能够分配一个新的
,是否可以接受,(使用新的校正颜色)对于键入为
Box
?@dlev的其他对象的属性,关于第一个选项,我需要一个更通用的解决方案,允许对象返回不可变对象,同时能够从内部修改它们。第二个选项将起作用,但出于某些原因,我希望将两个类分开:no
internal
access修饰符或嵌套类。@SimonV:介意我们问一下为什么不需要
内部
或嵌套类吗?这并不是说你不能绕过它,而是这个要求似乎有点做作。更一般地说,使用“with”似乎是常见的做法-方法在不可变对象上创建具有稍微修改的值的新实例,例如,
publicboxwithcolor(Color-Color)
。这个问题可能很愚蠢,但“with”是什么意思方法???-您只是在谈论工厂的命名约定吗?可能只是将框设为结构?或者您是在谈论对实例(而非静态)进行操作的
Clone()
方法的命名约定吗对象?@poke,除非
Box
需要成为另一个派生类的父类。这可能是个好主意,但是,可变性(或不可变性)与它是否是类或结构无关。很好的解决方案!如果使
Box
可变是“更难”的话会更好。当然,但你似乎不想这样”“真的吗"可变的。如果你这样做,你可以继续发展其他类,这些类会发生变化,同时向消费者呈现不可变的外观。这让我感到不舒服。任何允许在实例化后修改作为不可变对象发布的内容的内部状态的东西允许客户端误用,这可能会使依赖该不变性的其他客户端崩溃。必须使用新的不同接口才能访问这些其他方法的事实无助于希望值保持不变的客户端。这就是为什么我提到它不是真的不可变的。如果您希望为m打开一个类型