C# 私有成员访问的设计模式?
让我们用这个简单的例子: Connect4Board.cs: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
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的其他对象的属性,关于第一个选项,我需要一个更通用的解决方案,允许对象返回不可变对象,同时能够从内部修改它们。第二个选项将起作用,但出于某些原因,我希望将两个类分开:nointernal
access修饰符或嵌套类。@SimonV:介意我们问一下为什么不需要内部或嵌套类吗?这并不是说你不能绕过它,而是这个要求似乎有点做作。更一般地说,使用“with”似乎是常见的做法-方法在不可变对象上创建具有稍微修改的值的新实例,例如,publicboxwithcolor(Color-Color)
。这个问题可能很愚蠢,但“with”是什么意思方法???-您只是在谈论工厂的命名约定吗?可能只是将框设为结构?或者您是在谈论对实例(而非静态)进行操作的Clone()
方法的命名约定吗对象?@poke,除非Box
需要成为另一个派生类的父类。这可能是个好主意,但是,可变性(或不可变性)与它是否是类或结构无关。很好的解决方案!如果使Box
可变是“更难”的话会更好。当然,但你似乎不想这样”“真的吗"可变的。如果你这样做,你可以继续发展其他类,这些类会发生变化,同时向消费者呈现不可变的外观。这让我感到不舒服。任何允许在实例化后修改作为不可变对象发布的内容的内部状态的东西允许客户端误用,这可能会使依赖该不变性的其他客户端崩溃。必须使用新的不同接口才能访问这些其他方法的事实无助于希望值保持不变的客户端。这就是为什么我提到它不是真的不可变的。如果您希望为m打开一个类型